From 082d8d6623ccaa408a4533acfc8026a59616092f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Mon, 17 Sep 2012 15:31:38 +0200 Subject: [PATCH] Noux/net: refactoring of Socket_io_channel The Socket_io_channel class now uses the Io_channel_backend to provide the network related methods. In addition the Socket_io_channel_registry was replaced with a simpler implementation which uses Io_receptors to unblock I/O channels from the callback-function of lwip. --- ports/src/noux/child.h | 7 - ports/src/noux/main.cc | 10 +- ports/src/noux/minimal/dummy_net.cc | 4 - ports/src/noux/net/net.cc | 218 +++-------- .../src/noux/net/socket_descriptor_registry.h | 112 ------ ports/src/noux/net/socket_io_channel.h | 345 ++++++++++++------ 6 files changed, 288 insertions(+), 408 deletions(-) delete mode 100644 ports/src/noux/net/socket_descriptor_registry.h diff --git a/ports/src/noux/child.h b/ports/src/noux/child.h index 0c038b250..0d326b678 100644 --- a/ports/src/noux/child.h +++ b/ports/src/noux/child.h @@ -31,8 +31,6 @@ #include #include -extern void (*cleanup_socket_descriptors)(); - namespace Noux { /** @@ -74,7 +72,6 @@ namespace Noux { class User_info; User_info *user_info(); - class Child; bool is_init_process(Child *child); @@ -338,10 +335,6 @@ namespace Noux { ~Child() { - /* short-cut to close all remaining open sd's if the child exits */ - if (cleanup_socket_descriptors) - cleanup_socket_descriptors(); - _sig_rec->dissolve(&_execve_cleanup_dispatcher); _sig_rec->dissolve(&_exit_dispatcher); diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index 017c5f838..d54dd8e5f 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -38,9 +38,8 @@ namespace Noux { bool is_init_process(Child *child) { return child == init_child; } void init_process_exited() { init_child = 0; } -}; -extern void (*close_socket)(int); +}; extern void init_network(); @@ -230,13 +229,6 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) case SYSCALL_CLOSE: { - /** - * We have to explicitly close Socket_io_channel fd's because - * these are currently handled separately. - */ - if (close_socket) - close_socket(_sysio->close_in.fd); - remove_io_channel(_sysio->close_in.fd); return true; } diff --git a/ports/src/noux/minimal/dummy_net.cc b/ports/src/noux/minimal/dummy_net.cc index 9d1780f3c..7e5380fd9 100644 --- a/ports/src/noux/minimal/dummy_net.cc +++ b/ports/src/noux/minimal/dummy_net.cc @@ -14,10 +14,6 @@ /* local includes */ #include -void (*close_socket)(int) = 0; - -void (*cleanup_socket_descriptors)() = 0; - void init_network() { } bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) { return false; } diff --git a/ports/src/noux/net/net.cc b/ports/src/noux/net/net.cc index 29d18d9b8..b9df4370e 100644 --- a/ports/src/noux/net/net.cc +++ b/ports/src/noux/net/net.cc @@ -15,14 +15,15 @@ /* Genode includes */ #include #include +#include #include /* Noux includes */ #include -#include #include #include +#include /* Libc includes */ #include @@ -32,79 +33,30 @@ using namespace Noux; void (*libc_select_notify)(); -void (*close_socket)(int); -void (*cleanup_socket_descriptors)(); -/* set select() timeout to lwip's lowest possible value */ -struct timeval timeout = { 0, 10000 }; +/* helper macro for casting the backend */ +#define GET_SOCKET_IO_CHANNEL_BACKEND(backend, name) \ + Socket_io_channel_backend *name = \ + dynamic_cast(backend) +static Genode::Lock _select_notify_lock; /** * This callback function is called from lwip via the libc_select_notify * function pointer if an event occurs. */ - static void select_notify() { - fd_set readfds; - fd_set writefds; - fd_set exceptfds; - int ready; + /* + * The function could be called multiple times while actually + * still running. + */ + Genode::Lock::Guard guard(_select_notify_lock); - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - - /* for now set each currently used socket descriptor true */ - for (int sd = 0; sd < MAX_SOCKET_DESCRIPTORS; sd++) { - if (Socket_descriptor_registry::instance()->sd_in_use(sd)) { - int real_sd = Socket_descriptor_registry::instance()->io_channel_by_sd(sd)->get_socket(); - - FD_SET(real_sd, &readfds); - FD_SET(real_sd, &writefds); - FD_SET(real_sd, &exceptfds); - } + for (Io_receptor *r = io_receptor_registry()->first(); + r != 0; r = r->next()) { + r->check_and_wakeup(); } - - ready = ::select(MAX_SOCKET_DESCRIPTORS, &readfds, &writefds, &exceptfds, &timeout); - - /* if any socket is ready for reading */ - if (ready > 0) { - for (int sd = 0; sd < MAX_SOCKET_DESCRIPTORS; sd++) { - if (Socket_descriptor_registry::instance()->sd_in_use(sd)) { - int real_sd = Socket_descriptor_registry::instance()->io_channel_by_sd(sd)->get_socket(); - - if (FD_ISSET(real_sd, &readfds) - || FD_ISSET(real_sd, &writefds) - || FD_ISSET(real_sd, &exceptfds)) { - Shared_pointer sio = Socket_descriptor_registry::instance()->io_channel_by_sd(sd); - - if (FD_ISSET(real_sd, &readfds)) - sio->set_unblock(true, false, false); - if (FD_ISSET(real_sd, &writefds)) - sio->set_unblock(false, true, false); - if (FD_ISSET(real_sd, &exceptfds)) - sio->set_unblock(false, false, true); - - sio->invoke_all_notifiers(); - } - } - } - } -} - - -static void _close_socket(int sd) -{ - if (Socket_descriptor_registry::instance()->sd_in_use(sd)) { - Socket_descriptor_registry::instance()->remove_io_channel(sd); - } -} - - -static void _cleanup_socket_descriptors() -{ - Socket_descriptor_registry::instance()->reset_all(); } @@ -127,23 +79,12 @@ void init_network() if (!libc_select_notify) libc_select_notify = select_notify; - - if (!close_socket) - close_socket = _close_socket; - - if (!cleanup_socket_descriptors) - cleanup_socket_descriptors = _cleanup_socket_descriptors; } /********************************* ** Noux net syscall dispatcher ** *********************************/ -#define GET_SOCKET_IO_CHANNEL(fd, handle) \ - Shared_pointer io = _lookup_channel(fd); \ - Shared_pointer handle = \ - io.dynamic_pointer_cast(); - bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) { switch (sc) { @@ -184,7 +125,9 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) { Socket_io_channel *socket_io_channel = new Socket_io_channel(); - if (!socket_io_channel->socket(_sysio)) { + GET_SOCKET_IO_CHANNEL_BACKEND(socket_io_channel->backend(), backend); + + if (!backend->socket(_sysio)) { delete socket_io_channel; return false; } @@ -193,155 +136,112 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) _sysio->socket_out.fd = add_io_channel(io_channel); - /* add socket to registry */ - Socket_descriptor_registry::instance()->add_io_channel(io_channel.dynamic_pointer_cast(), - _sysio->socket_out.fd); - return true; } case SYSCALL_GETSOCKOPT: { - GET_SOCKET_IO_CHANNEL(_sysio->getsockopt_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->getsockopt_in.fd); - if (!socket_io_channel->getsockopt(_sysio)) - return false; + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return true; + return backend->getsockopt(_sysio); } case SYSCALL_SETSOCKOPT: { - GET_SOCKET_IO_CHANNEL(_sysio->setsockopt_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->setsockopt_in.fd); - if (!socket_io_channel->setsockopt(_sysio)) { - return false; - } + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return true; + return backend->setsockopt(_sysio); } case SYSCALL_ACCEPT: { - GET_SOCKET_IO_CHANNEL(_sysio->accept_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->accept_in.fd); - int new_socket = socket_io_channel->accept(_sysio); - if (new_socket == -1) + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); + + int socket = backend->accept(_sysio); + if (socket == -1) return false; - Socket_io_channel *new_socket_io_channel = new Socket_io_channel(new_socket); - Shared_pointer channel(new_socket_io_channel, Genode::env()->heap()); + Socket_io_channel *socket_io_channel = new Socket_io_channel(socket); + Shared_pointer io_channel(socket_io_channel, Genode::env()->heap()); - _sysio->accept_out.fd = add_io_channel(channel); - - /* add new socket to registry */ - Socket_descriptor_registry::instance()->add_io_channel(channel.dynamic_pointer_cast(), - _sysio->accept_out.fd); + _sysio->accept_out.fd = add_io_channel(io_channel); return true; } case SYSCALL_BIND: { - GET_SOCKET_IO_CHANNEL(_sysio->bind_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->bind_in.fd); - if (socket_io_channel->bind(_sysio) == -1) - return false; + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return true; + return (backend->bind(_sysio) == -1) ? false : true; } case SYSCALL_LISTEN: { - GET_SOCKET_IO_CHANNEL(_sysio->listen_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->listen_in.fd); - if (socket_io_channel->listen(_sysio) == -1) - return false; + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - return true; + return (backend->listen(_sysio) == -1) ? false : true; } case SYSCALL_SEND: { - GET_SOCKET_IO_CHANNEL(_sysio->send_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->send_in.fd); - ssize_t len = socket_io_channel->send(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (len == -1) - return false; - - _sysio->send_out.len = len; - - return true; + return (backend->send(_sysio) == -1) ? false : true; } case SYSCALL_SENDTO: { - GET_SOCKET_IO_CHANNEL(_sysio->sendto_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->sendto_in.fd); - ssize_t len = socket_io_channel->sendto(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (len == -1) - return false; - - _sysio->sendto_out.len = len; - - return true; + return (backend->sendto(_sysio) == -1) ? false : true; } case SYSCALL_RECV: { - GET_SOCKET_IO_CHANNEL(_sysio->recv_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->recv_in.fd); - ssize_t len = socket_io_channel->recv(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (len == -1) - return false; - - _sysio->recv_out.len = len; - - return true; + return (backend->recv(_sysio) == -1) ? false : true; } case SYSCALL_RECVFROM: { - GET_SOCKET_IO_CHANNEL(_sysio->recvfrom_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->recvfrom_in.fd); - ssize_t len = socket_io_channel->recvfrom(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (len == -1) - return false; - - _sysio->recvfrom_out.len = len; - - return true; + return (backend->recvfrom(_sysio) == -1) ? false : true; } case SYSCALL_GETPEERNAME: { - GET_SOCKET_IO_CHANNEL(_sysio->getpeername_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->getpeername_in.fd); - int res = socket_io_channel->getpeername(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (res == -1) - return false; - - return true; + return (backend->getpeername(_sysio) == -1) ? false : true; } case SYSCALL_SHUTDOWN: { - GET_SOCKET_IO_CHANNEL(_sysio->shutdown_in.fd, socket_io_channel) + Shared_pointer io = _lookup_channel(_sysio->shutdown_in.fd); - int res = socket_io_channel->shutdown(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (res == -1) - return false; - - /* remove sd from registry */ - _close_socket(_sysio->shutdown_in.fd); - - return true; + return (backend->shutdown(_sysio) == -1) ? false : true; } case SYSCALL_CONNECT: { - GET_SOCKET_IO_CHANNEL(_sysio->connect_in.fd, socket_io_channel); + Shared_pointer io = _lookup_channel(_sysio->connect_in.fd); - int res = socket_io_channel->connect(_sysio); + GET_SOCKET_IO_CHANNEL_BACKEND(io->backend(), backend); - if (res == -1) - return false; - - return true; + return (backend->connect(_sysio) == -1) ? false : true; } } diff --git a/ports/src/noux/net/socket_descriptor_registry.h b/ports/src/noux/net/socket_descriptor_registry.h deleted file mode 100644 index 4dbee1684..000000000 --- a/ports/src/noux/net/socket_descriptor_registry.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * \brief I/O channel for sockets - * \author Josef Söntgen - * \date 2012-04-12 - */ - -/* - * Copyright (C) 2011-2012 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - - -#ifndef _NOUX__SOCKET_DESCRIPTOR_REGISTRY_H_ -#define _NOUX__SOCKET_DESCRIPTOR_REGISTRY_H_ - -/* Noux includes */ -#include - -namespace Noux { - - enum { MAX_SOCKET_DESCRIPTORS = 64 }; - - template - class Socket_descriptor_registry - { - private: - - struct { - bool allocated; - Shared_pointer io_channel; - } _sds[MAX_SOCKET_DESCRIPTORS]; - - void _assign_sd(int sd, Shared_pointer &io_channel) - { - _sds[sd].io_channel = io_channel; - _sds[sd].allocated = true; - } - - bool _is_valid_sd(int sd) const - { - return (sd >= 0) && (sd < MAX_SOCKET_DESCRIPTORS); - } - - void _reset_sd(int sd) - { - _sds[sd].io_channel = Shared_pointer(); - _sds[sd].allocated = false; - } - - public: - Socket_descriptor_registry() - { - for (unsigned i = 0; i < MAX_SOCKET_DESCRIPTORS; i++) - _reset_sd(i); - } - - void reset_all() - { - for (unsigned i = 0; i < MAX_SOCKET_DESCRIPTORS; i++) - _reset_sd(i); - } - - int add_io_channel(Shared_pointer io_channel, int sd = -1) - { - if (sd == -1) { - PERR("Could not allocate socket descriptor"); - return -1; - } - - if (!_is_valid_sd(sd)) { - PERR("Socket descriptor %d is out of range", sd); - return -2; - } - - _assign_sd(sd, io_channel); - return sd; - } - - void remove_io_channel(int sd) - { - if (!_is_valid_sd(sd)) - PERR("Socket descriptor %d is out of range", sd); - else - _reset_sd(sd); - } - - bool sd_in_use(int sd) const - { - return (_is_valid_sd(sd) && _sds[sd].allocated); - } - - Shared_pointer io_channel_by_sd(int sd) const - { - if (!sd_in_use(sd)) { - PWRN("Socket descriptor %d is not open", sd); - return Shared_pointer(); - } - - return _sds[sd].io_channel; - } - - static Socket_descriptor_registry *instance() - { - static Socket_descriptor_registry _sdr; - return &_sdr; - } - }; - -}; -#endif /* _NOUX__SOCKET_DESCRIPTOR_REGISTRY_H_ */ diff --git a/ports/src/noux/net/socket_io_channel.h b/ports/src/noux/net/socket_io_channel.h index ba3acc15e..648948bdb 100644 --- a/ports/src/noux/net/socket_io_channel.h +++ b/ports/src/noux/net/socket_io_channel.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -33,89 +35,39 @@ namespace Noux { - class Socket_io_channel : public Io_channel + class Socket_io_channel_backend : public Io_channel_backend { private: int _socket; - enum { UNBLOCK_READ = 0x1, - UNBLOCK_WRITE = 0x2, - UNBLOCK_EXCEPT = 0x4 }; - - int _unblock; - public: - Socket_io_channel() + Socket_io_channel_backend() : - _socket(-1), - _unblock(0) + _socket(-1) { } - Socket_io_channel(int s) + Socket_io_channel_backend(int s) : - _socket(s), - _unblock(0) + _socket(s) { } - ~Socket_io_channel() + ~Socket_io_channel_backend() { - if (_socket != -1) + if (_socket != -1) { ::shutdown(_socket, SHUT_RDWR); - } - - int get_socket() const - { - return _socket; - } - - void set_unblock(bool rd, bool wr, bool ex) - { - if (rd) - _unblock |= UNBLOCK_READ; - if (wr) - _unblock |= UNBLOCK_WRITE; - if (ex) - _unblock |= UNBLOCK_EXCEPT; - } - - bool fstat(Sysio *sysio) { return false; } - - bool fcntl(Sysio *sysio) - { - switch (sysio->fcntl_in.cmd) { - - case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: - case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS: - { - int result = ::fcntl(_socket, sysio->fcntl_in.cmd, - sysio->fcntl_in.long_arg); - - sysio->fcntl_out.result = result; - return true; - } - default: - PWRN("invalid fcntl command: %d", sysio->fcntl_in.cmd); - sysio->error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID; - - return false; + ::close(_socket); } } - bool dirent(Sysio *sysio) { return false; } + int type() const { return 1; } - bool check_unblock(bool rd, bool wr, bool ex) const - { - if (_unblock & UNBLOCK_READ) - return true; - if (_unblock & UNBLOCK_WRITE) - return true; - if (_unblock & UNBLOCK_EXCEPT) - return true; + int socket() const { return _socket; } - return false; - } + /** + * Io_channel interface implementation (only needed methods) + */ bool write(Sysio *sysio, size_t &count) { @@ -135,7 +87,8 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } return false; @@ -143,9 +96,7 @@ namespace Noux { bool read(Sysio *sysio) { - size_t const max_count = - Genode::min(sysio->read_in.count, - sizeof(sysio->read_out.chunk)); + size_t const max_count = Genode::min(sysio->read_in.count, sizeof(sysio->read_out.chunk)); ssize_t result = ::read(_socket, sysio->read_out.chunk, max_count); @@ -160,56 +111,106 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } return false; } - bool socket(Sysio *sysio) + bool fcntl(Sysio *sysio) { - _socket = ::socket(sysio->socket_in.domain, - sysio->socket_in.type, - sysio->socket_in.protocol); + int cmd = -1; + switch (sysio->fcntl_in.cmd) { - return (_socket == -1) ? false : true; - } - - bool getsockopt(Sysio *sysio) - { - int result = ::getsockopt(_socket, sysio->getsockopt_in.level, - sysio->getsockopt_in.optname, - sysio->getsockopt_in.optval, - &sysio->getsockopt_in.optlen); - - return (result == -1) ? false : true; - } - - bool setsockopt(Sysio *sysio) - { - /* - * Filter options out because lwip only supports several socket - * options. Therefore for now we silently return 0 and notify - * the user via debug message. - */ - switch (sysio->setsockopt_in.optname) { - case SO_DEBUG: - case SO_LINGER: - case SO_REUSEADDR: - - PWRN("SOL_SOCKET option '%d' is currently not supported, however we report success", - sysio->setsockopt_in.optname); - return true; + case Sysio::FCNTL_CMD_GET_FILE_STATUS_FLAGS: cmd = F_GETFL; break; + case Sysio::FCNTL_CMD_SET_FILE_STATUS_FLAGS: cmd = F_SETFL; break; + default: + PDBG("invalid fcntl command: %d", sysio->fcntl_in.cmd); + sysio->error.fcntl = Sysio::FCNTL_ERR_CMD_INVALID; + return false; } - int result = ::setsockopt(_socket, sysio->setsockopt_in.level, - sysio->setsockopt_in.optname, - sysio->setsockopt_in.optval, - sysio->setsockopt_in.optlen); + int result = ::fcntl(_socket, cmd, sysio->fcntl_in.long_arg); - return (result == -1) ? false : true; + sysio->fcntl_out.result = result; + return true; } + bool dirent(Sysio *sysio) { return false; } + + bool ioctl(Sysio *sysio) + { + int request; + + switch (sysio->ioctl_in.request) { + + case Sysio::Ioctl_in::OP_FIONBIO: request = FIONBIO; break; + default: + PDBG("invalid ioctl request: %d", sysio->ioctl_in.request); + return false; + } + int result = ::ioctl(_socket, request, NULL); + + return result ? false : true; + } + + bool check_unblock(bool rd, bool wr, bool ex) const + { + fd_set readfds; + fd_set writefds; + fd_set exceptfds; + int ready; + + /** + * The timeout will be overriden in libc's select() function + * but we still need a valid pointer because libc's select() + * will block forever otherwise. + */ + struct timeval timeout = { 0, 0 }; + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + + FD_SET(_socket, &readfds); + FD_SET(_socket, &writefds); + FD_SET(_socket, &exceptfds); + + ready = ::select(_socket + 1, &readfds, &writefds, &exceptfds, &timeout); + + if (ready > 0) { + if (rd) { + if (FD_ISSET(_socket, &readfds)) + return true; + } + + if (wr) { + if (FD_ISSET(_socket, &writefds)) + return true; + } + + if (ex) { + if (FD_ISSET(_socket, &exceptfds)) + return true; + } + } + + /** + * HACK: Since lwip won't mark fds as writable, even if they + * are, if asked multiple times we return true in this + * case. Hopefully that won't break any time soon. + */ + if (wr) + return true; + + return false; + } + + /** + * Socket methods + */ + int accept(Sysio *sysio) { int result; @@ -230,7 +231,8 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } @@ -249,7 +251,8 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } @@ -269,7 +272,8 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } @@ -282,11 +286,14 @@ namespace Noux { (socklen_t *)&sysio->getpeername_in.addrlen); } - bool ioctl(Sysio *sysio) + bool getsockopt(Sysio *sysio) { - int result = ::ioctl(_socket, sysio->ioctl_in.request, NULL); + int result = ::getsockopt(_socket, sysio->getsockopt_in.level, + sysio->getsockopt_in.optname, + sysio->getsockopt_in.optval, + &sysio->getsockopt_in.optlen); - return result ? false : true; + return (result == -1) ? false : true; } int listen(Sysio *sysio) @@ -298,7 +305,8 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } @@ -316,10 +324,13 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } + sysio->recv_out.len = result; + return result; } @@ -336,13 +347,39 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } + sysio->recvfrom_out.len = result; + return result; } + bool setsockopt(Sysio *sysio) + { + /* + * Filter options out because lwip only supports several socket + * options. Therefore for now we silently return 0 and notify + * the user via debug message. + */ + switch (sysio->setsockopt_in.optname) { + case SO_DEBUG: + case SO_LINGER: + PWRN("SOL_SOCKET option '%d' is currently not supported, however we report success", + sysio->setsockopt_in.optname); + return true; + } + + int result = ::setsockopt(_socket, sysio->setsockopt_in.level, + sysio->setsockopt_in.optname, + sysio->setsockopt_in.optval, + sysio->setsockopt_in.optlen); + + return (result == -1) ? false : true; + } + ssize_t send(Sysio *sysio) { ssize_t result = ::send(_socket, sysio->send_in.buf, sysio->send_in.len, @@ -357,10 +394,13 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } + sysio->send_out.len = result; + return result; } @@ -380,10 +420,13 @@ namespace Noux { 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; + PDBG("unhandled errno: %d", errno); + break; } } + sysio->sendto_out.len = result; + return result; } @@ -395,12 +438,80 @@ namespace Noux { switch (errno) { case ENOTCONN: sysio->error.shutdown = Sysio::SHUTDOWN_ERR_NOT_CONNECTED; break; default: - PDBG("unhandled errno: %d", errno); break; + PDBG("unhandled errno: %d", errno); + break; } } return result; } + + bool socket(Sysio *sysio) + { + _socket = ::socket(sysio->socket_in.domain, + sysio->socket_in.type, + sysio->socket_in.protocol); + + return (_socket == -1) ? false : true; + } + }; + + class Socket_io_channel : public Io_channel + { + private: + + + Socket_io_channel_backend *_backend; + + public: + + Socket_io_channel() + : + _backend(new (env()->heap()) Socket_io_channel_backend()) + { } + + Socket_io_channel(int s) + : + _backend(new (env()->heap()) Socket_io_channel_backend(s)) + { } + + ~Socket_io_channel() + { + destroy(env()->heap(), _backend); + } + + /** + * Io_channel interface (only needed methods) + */ + + Io_channel_backend *backend() { return _backend; } + + bool write(Sysio *sysio, size_t &count) + { + return _backend->write(sysio, count); + } + + bool read(Sysio *sysio) + { + return _backend->read(sysio); + } + + bool fcntl(Sysio* sysio) + { + return _backend->fcntl(sysio); + } + + bool ioctl(Sysio *sysio) + { + return _backend->ioctl(sysio); + } + + bool check_unblock(bool rd, bool wr, bool ex) const + { + return _backend->check_unblock(rd, wr, ex); + } + + }; }