diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index f3cf19b8b0..1cdd65d5fb 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -299,6 +299,42 @@ namespace Noux { MKDIR_ERR_NO_SPACE, MKDIR_ERR_NO_PERM, MKDIR_ERR_NAME_TOO_LONG}; + enum Read_error { READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK, + READ_ERR_INVALID, READ_ERR_IO }; + + enum Write_error { WRITE_ERR_AGAIN, WRITE_ERR_WOULD_BLOCK, + WRITE_ERR_INVALID, WRITE_ERR_IO }; + + /** + * Socket related errors + */ + enum Accept_error { ACCEPT_ERR_AGAIN, ACCEPT_ERR_WOULD_BLOCK, + ACCEPT_ERR_INVALID, ACCEPT_ERR_NO_MEMORY, + ACCEPT_ERR_NOT_SUPPORTED }; + + enum Bind_error { BIND_ERR_ACCESS, BIND_ERR_ADDR_IN_USE, + BIND_ERR_INVALID, BIND_ERR_NO_MEMORY }; + + enum Connect_error { CONNECT_ERR_ACCESS, CONNECT_ERR_AGAIN, + CONNECT_ERR_ALREADY, CONNECT_ERR_CONN_REFUSED, + CONNECT_ERR_NO_PERM, CONNECT_ERR_ADDR_IN_USE, + CONNECT_ERR_IN_PROGRESS, CONNECT_ERR_IS_CONNECTED }; + + enum Listen_error { LISTEN_ERR_ADDR_IN_USE, LISTEN_ERR_NOT_SUPPORTED }; + + enum Recv_error { RECV_ERR_AGAIN, RECV_ERR_WOULD_BLOCK, + RECV_ERR_CONN_REFUSED, RECV_ERR_INVALID, + RECV_ERR_NOT_CONNECTED, RECV_ERR_NO_MEMORY }; + + enum Send_error { SEND_ERR_AGAIN, SEND_ERR_WOULD_BLOCK, + SEND_ERR_CONNECTION_RESET, SEND_ERR_INVALID, + SEND_ERR_IS_CONNECTED, SEND_ERR_NO_MEMORY }; + + enum Shutdown_error { SHUTDOWN_ERR_NOT_CONNECTED }; + + enum Socket_error { SOCKET_ERR_ACCESS, SOCKET_ERR_NO_AF_SUPPORT, + SOCKET_ERR_INVALID, SOCKET_ERR_NO_MEMORY }; + union { General_error general; Stat_error stat; @@ -310,6 +346,16 @@ namespace Noux { Unlink_error unlink; Rename_error rename; Mkdir_error mkdir; + Read_error read; + Write_error write; + Accept_error accept; + Bind_error bind; + Connect_error connect; + Listen_error listen; + Recv_error recv; + Send_error send; + Shutdown_error shutdown; + Socket_error socket; } error; union { diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 371db8f710..feaeb8d24c 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -774,7 +774,18 @@ namespace { Genode::memcpy(sysio()->write_in.chunk, src, curr_count); if (!noux()->syscall(Noux::Session::SYSCALL_WRITE)) { - PERR("write error %d (fd %d)", sysio()->error.general, noux_fd(fd->context)); + switch (sysio()->error.write) { + case Noux::Sysio::WRITE_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::WRITE_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + case Noux::Sysio::WRITE_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::WRITE_ERR_IO: errno = EIO; break; + default: + if (sysio()->error.general == Noux::Sysio::ERR_FD_INVALID) + errno = EBADF; + else + errno = 0; + break; + } } count -= curr_count; @@ -797,8 +808,18 @@ namespace { sysio()->read_in.count = curr_count; if (!noux()->syscall(Noux::Session::SYSCALL_READ)) { - PERR("read error"); - /* XXX set errno */ + switch (sysio()->error.read) { + case Noux::Sysio::READ_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::READ_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + case Noux::Sysio::READ_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::READ_ERR_IO: errno = EIO; break; + default: + if (sysio()->error.general == Noux::Sysio::ERR_FD_INVALID) + errno = EBADF; + else + errno = 0; + break; + } return -1; } @@ -1321,6 +1342,15 @@ namespace { } if (!noux()->syscall(Noux::Session::SYSCALL_ACCEPT)) { + switch (sysio()->error.accept) { + case Noux::Sysio::ACCEPT_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::ACCEPT_ERR_NO_MEMORY: errno = ENOMEM; break; + case Noux::Sysio::ACCEPT_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::ACCEPT_ERR_NOT_SUPPORTED: errno = EOPNOTSUPP; break; + case Noux::Sysio::ACCEPT_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + default: errno = 0; break; + } + return 0; } @@ -1330,7 +1360,6 @@ namespace { Libc::Plugin_context *context = noux_context(sysio()->accept_out.fd); return Libc::file_descriptor_allocator()->alloc(this, context, sysio()->accept_out.fd); - } @@ -1343,7 +1372,13 @@ namespace { sysio()->bind_in.addrlen = addrlen; if (!noux()->syscall(Noux::Session::SYSCALL_BIND)) { - errno = EACCES; + switch (sysio()->error.bind) { + case Noux::Sysio::BIND_ERR_ACCESS: errno = EACCES; break; + case Noux::Sysio::BIND_ERR_ADDR_IN_USE: errno = EADDRINUSE; break; + case Noux::Sysio::BIND_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::BIND_ERR_NO_MEMORY: errno = ENOMEM; break; + default: errno = 0; break; + } return -1; } @@ -1360,7 +1395,14 @@ namespace { sysio()->connect_in.addrlen = addrlen; if (!noux()->syscall(Noux::Session::SYSCALL_CONNECT)) { - /* XXX errno */ + switch (sysio()->error.connect) { + case Noux::Sysio::CONNECT_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::CONNECT_ERR_ALREADY: errno = EALREADY; break; + case Noux::Sysio::CONNECT_ERR_ADDR_IN_USE: errno = EADDRINUSE; break; + case Noux::Sysio::CONNECT_ERR_IN_PROGRESS: errno = EINPROGRESS; break; + case Noux::Sysio::CONNECT_ERR_IS_CONNECTED: errno = EISCONN; break; + default: errno = 0; break; + } return -1; } @@ -1393,7 +1435,11 @@ namespace { sysio()->listen_in.backlog = backlog; if (!noux()->syscall(Noux::Session::SYSCALL_LISTEN)) { - /* errno = EACCES; */ + switch (sysio()->error.listen) { + case Noux::Sysio::LISTEN_ERR_ADDR_IN_USE: errno = EADDRINUSE; break; + case Noux::Sysio::LISTEN_ERR_NOT_SUPPORTED: errno = EOPNOTSUPP; break; + default: errno = 0; break; + } return -1; } @@ -1413,7 +1459,13 @@ namespace { sysio()->recv_in.len = curr_len; if (!noux()->syscall(Noux::Session::SYSCALL_RECV)) { - /* XXX set errno */ + switch (sysio()->error.recv) { + case Noux::Sysio::RECV_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::RECV_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + case Noux::Sysio::RECV_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::RECV_ERR_NOT_CONNECTED: errno = ENOTCONN; break; + default: errno = 0; break; + } return -1; } @@ -1452,7 +1504,13 @@ namespace { sysio()->recvfrom_in.addrlen = *addrlen; if (!noux()->syscall(Noux::Session::SYSCALL_RECVFROM)) { - /* XXX set errno */ + switch (sysio()->error.recv) { + case Noux::Sysio::RECV_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::RECV_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + case Noux::Sysio::RECV_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::RECV_ERR_NOT_CONNECTED: errno = ENOTCONN; break; + default: errno = 0; break; + } return -1; } @@ -1495,6 +1553,16 @@ namespace { if (!noux()->syscall(Noux::Session::SYSCALL_SEND)) { PERR("write error %d", sysio()->error.general); + switch (sysio()->error.send) { + case Noux::Sysio::SEND_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::SEND_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + case Noux::Sysio::SEND_ERR_CONNECTION_RESET: errno = ECONNRESET; break; + case Noux::Sysio::SEND_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::SEND_ERR_IS_CONNECTED: errno = EISCONN; break; + case Noux::Sysio::SEND_ERR_NO_MEMORY: errno = ENOMEM; break; + default: errno = 0; break; + } + /* return foo */ } len -= curr_len; @@ -1510,7 +1578,7 @@ namespace { int const orig_count = len; if (addrlen > sizeof (sysio()->sendto_in.dest_addr)) { - /* XXX errno */ + errno = 0; /* XXX */ return -1; } @@ -1535,6 +1603,15 @@ namespace { } if (!noux()->syscall(Noux::Session::SYSCALL_SENDTO)) { + switch (sysio()->error.send) { + case Noux::Sysio::SEND_ERR_AGAIN: errno = EAGAIN; break; + case Noux::Sysio::SEND_ERR_WOULD_BLOCK: errno = EWOULDBLOCK; break; + case Noux::Sysio::SEND_ERR_CONNECTION_RESET: errno = ECONNRESET; break; + case Noux::Sysio::SEND_ERR_INVALID: errno = EINVAL; break; + case Noux::Sysio::SEND_ERR_IS_CONNECTED: errno = EISCONN; break; + case Noux::Sysio::SEND_ERR_NO_MEMORY: errno = ENOMEM; break; + default: errno = 0; break; + } return -1; } @@ -1552,6 +1629,10 @@ namespace { sysio()->shutdown_in.how = how; if (!noux()->syscall(Noux::Session::SYSCALL_SHUTDOWN)) { + switch (sysio()->error.shutdown) { + case Noux::Sysio::SHUTDOWN_ERR_NOT_CONNECTED: errno = ENOTCONN; break; + default: errno = 0; break; + } return -1; } diff --git a/ports/src/noux/net/socket_io_channel.h b/ports/src/noux/net/socket_io_channel.h index 52139bb2ec..6fcef63337 100644 --- a/ports/src/noux/net/socket_io_channel.h +++ b/ports/src/noux/net/socket_io_channel.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace Noux { @@ -119,7 +120,7 @@ namespace Noux { bool write(Sysio *sysio, size_t &count) { - size_t result = ::write(_socket, sysio->write_in.chunk, + ssize_t result = ::write(_socket, sysio->write_in.chunk, sysio->write_in.count); if (result > -1) { @@ -129,6 +130,15 @@ namespace Noux { return true; } + switch (errno) { + /* case EAGAIN: sysio->error.read = Sysio::READ_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio->error.read = Sysio::READ_ERR_WOULD_BLOCK; break; + case EINVAL: sysio->error.read = Sysio::READ_ERR_INVALID; break; + case EIO: sysio->error.read = Sysio::READ_ERR_IO; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + return false; } @@ -138,10 +148,23 @@ namespace Noux { Genode::min(sysio->read_in.count, sizeof(sysio->read_out.chunk)); - sysio->read_out.count = ::read(_socket, sysio->read_out.chunk, - max_count); + ssize_t result = ::read(_socket, sysio->read_out.chunk, max_count); - return true; + if (result > -1) { + sysio->read_out.count = result; + return true; + } + + switch (errno) { + /* case EAGAIN: sysio->error.read = Sysio::READ_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio->error.read = Sysio::READ_ERR_WOULD_BLOCK; break; + case EINVAL: sysio->error.read = Sysio::READ_ERR_INVALID; break; + case EIO: sysio->error.read = Sysio::READ_ERR_IO; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + + return false; } bool socket(Sysio *sysio) @@ -200,19 +223,58 @@ namespace Noux { &sysio->accept_in.addrlen); } + if (result == -1) { + switch (errno) { + /* case EAGAIN: sysio->error.accept = Sysio::ACCEPT_ERR_AGAIN; break; */ + case ENOMEM: sysio->error.accept = Sysio::ACCEPT_ERR_NO_MEMORY; break; + case EINVAL: sysio->error.accept = Sysio::ACCEPT_ERR_INVALID; break; + case EOPNOTSUPP: sysio->error.accept = Sysio::ACCEPT_ERR_NOT_SUPPORTED; break; + case EWOULDBLOCK: sysio->error.accept = Sysio::ACCEPT_ERR_WOULD_BLOCK; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + return result; } int bind(Sysio *sysio) { - return ::bind(_socket, (const struct sockaddr *)&sysio->bind_in.addr, - sysio->bind_in.addrlen); + int result = ::bind(_socket, (const struct sockaddr *)&sysio->bind_in.addr, + sysio->bind_in.addrlen); + + if (result == -1) { + switch (errno) { + case EACCES: sysio->error.bind = Sysio::BIND_ERR_ACCESS; break; + case EADDRINUSE: sysio->error.bind = Sysio::BIND_ERR_ADDR_IN_USE; break; + case EINVAL: sysio->error.bind = Sysio::BIND_ERR_INVALID; break; + case ENOMEM: sysio->error.bind = Sysio::BIND_ERR_NO_MEMORY; break; + default: + PERR("unhandled errno: %d", errno); break; + } + } + + return result; } int connect(Sysio *sysio) { - return ::connect(_socket, (struct sockaddr *)&sysio->connect_in.addr, - sysio->connect_in.addrlen); + int result = ::connect(_socket, (struct sockaddr *)&sysio->connect_in.addr, + sysio->connect_in.addrlen); + + if (result == -1) { + switch (errno) { + case EAGAIN: sysio->error.connect = Sysio::CONNECT_ERR_AGAIN; break; + case EALREADY: sysio->error.connect = Sysio::CONNECT_ERR_ALREADY; break; + case EADDRINUSE: sysio->error.connect = Sysio::CONNECT_ERR_ADDR_IN_USE; break; + case EINPROGRESS: sysio->error.connect = Sysio::CONNECT_ERR_IN_PROGRESS; break; + case EISCONN: sysio->error.connect = Sysio::CONNECT_ERR_IS_CONNECTED; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + + return result; } int getpeername(Sysio *sysio) @@ -230,13 +292,36 @@ namespace Noux { int listen(Sysio *sysio) { - return ::listen(_socket, sysio->listen_in.backlog); + int result = ::listen(_socket, sysio->listen_in.backlog); + + if (result == -1) { + switch (errno) { + case EADDRINUSE: sysio->error.listen = Sysio::LISTEN_ERR_ADDR_IN_USE; break; + case EOPNOTSUPP: sysio->error.listen = Sysio::LISTEN_ERR_NOT_SUPPORTED; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + + return result; } ssize_t recv(Sysio *sysio) { - return ::recv(_socket, sysio->recv_in.buf, sysio->recv_in.len, - sysio->recv_in.flags); + ssize_t result = ::recv(_socket, sysio->recv_in.buf, sysio->recv_in.len, sysio->recv_in.flags); + + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio->error.recv = Sysio::RECV_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio->error.recv = Sysio::RECV_ERR_WOULD_BLOCK; break; + case EINVAL: sysio->error.recv = Sysio::RECV_ERR_INVALID; break; + case ENOTCONN: sysio->error.recv = Sysio::RECV_ERR_NOT_CONNECTED; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + + return result; } ssize_t recvfrom(Sysio *sysio) @@ -245,13 +330,39 @@ namespace Noux { sysio->recv_in.flags, (struct sockaddr *)&sysio->recvfrom_in.src_addr, &sysio->recvfrom_in.addrlen); + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio->error.recv = Sysio::RECV_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio->error.recv = Sysio::RECV_ERR_WOULD_BLOCK; break; + case EINVAL: sysio->error.recv = Sysio::RECV_ERR_INVALID; break; + case ENOTCONN: sysio->error.recv = Sysio::RECV_ERR_NOT_CONNECTED; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + return result; } ssize_t send(Sysio *sysio) { - return ::send(_socket, sysio->send_in.buf, sysio->send_in.len, - sysio->send_in.flags); + ssize_t result = ::send(_socket, sysio->send_in.buf, sysio->send_in.len, + sysio->send_in.flags); + + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio->error.send = Sysio::SEND_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio->error.send = Sysio::SEND_ERR_WOULD_BLOCK; break; + case ECONNRESET: sysio->error.send = Sysio::SEND_ERR_CONNECTION_RESET; break; + case EINVAL: sysio->error.send = Sysio::SEND_ERR_INVALID; break; + case EISCONN: sysio->error.send = Sysio::SEND_ERR_IS_CONNECTED; break; + case ENOMEM: sysio->error.send = Sysio::SEND_ERR_NO_MEMORY; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + + return result; } ssize_t sendto(Sysio *sysio) @@ -261,12 +372,35 @@ namespace Noux { (const struct sockaddr *) &sysio->sendto_in.dest_addr, sysio->sendto_in.addrlen); + if (result == -1) { + switch (errno) { + /*case EAGAIN: sysio->error.send = Sysio::SEND_ERR_AGAIN; break; */ + case EWOULDBLOCK: sysio->error.send = Sysio::SEND_ERR_WOULD_BLOCK; break; + case ECONNRESET: sysio->error.send = Sysio::SEND_ERR_CONNECTION_RESET; break; + case EINVAL: sysio->error.send = Sysio::SEND_ERR_INVALID; break; + case EISCONN: sysio->error.send = Sysio::SEND_ERR_IS_CONNECTED; break; + case ENOMEM: sysio->error.send = Sysio::SEND_ERR_NO_MEMORY; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + return result; } int shutdown(Sysio *sysio) { - return ::shutdown(_socket, sysio->shutdown_in.how); + int result = ::shutdown(_socket, sysio->shutdown_in.how); + + if (result == -1) { + switch (errno) { + case ENOTCONN: sysio->error.shutdown = Sysio::SHUTDOWN_ERR_NOT_CONNECTED; break; + default: + PDBG("unhandled errno: %d", errno); break; + } + } + + return result; } }; }