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.
This commit is contained in:
Josef Söntgen 2012-09-17 15:31:38 +02:00
parent 08bd41b1ec
commit 082d8d6623
6 changed files with 288 additions and 408 deletions

View File

@ -31,8 +31,6 @@
#include <cpu_session_component.h>
#include <child_policy.h>
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);

View File

@ -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;
}

View File

@ -14,10 +14,6 @@
/* local includes */
#include <child.h>
void (*close_socket)(int) = 0;
void (*cleanup_socket_descriptors)() = 0;
void init_network() { }
bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) { return false; }

View File

@ -15,14 +15,15 @@
/* Genode includes */
#include <cap_session/connection.h>
#include <dataspace/client.h>
#include <base/lock.h>
#include <lwip/genode.h>
/* Noux includes */
#include <child.h>
#include <socket_descriptor_registry.h>
#include <socket_io_channel.h>
#include <shared_pointer.h>
#include <io_receptor_registry.h>
/* Libc includes */
#include <sys/select.h>
@ -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<Socket_io_channel_backend*>(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<Socket_io_channel>::instance()->sd_in_use(sd)) {
int real_sd = Socket_descriptor_registry<Socket_io_channel>::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<Socket_io_channel>::instance()->sd_in_use(sd)) {
int real_sd = Socket_descriptor_registry<Socket_io_channel>::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<Socket_io_channel> sio = Socket_descriptor_registry<Socket_io_channel>::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<Socket_io_channel>::instance()->sd_in_use(sd)) {
Socket_descriptor_registry<Socket_io_channel>::instance()->remove_io_channel(sd);
}
}
static void _cleanup_socket_descriptors()
{
Socket_descriptor_registry<Socket_io_channel>::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_channel> io = _lookup_channel(fd); \
Shared_pointer<Socket_io_channel> handle = \
io.dynamic_pointer_cast<Socket_io_channel>();
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<Socket_io_channel>::instance()->add_io_channel(io_channel.dynamic_pointer_cast<Socket_io_channel>(),
_sysio->socket_out.fd);
return true;
}
case SYSCALL_GETSOCKOPT:
{
GET_SOCKET_IO_CHANNEL(_sysio->getsockopt_in.fd, socket_io_channel)
Shared_pointer<Io_channel> 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_channel> 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_channel> 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<Io_channel> channel(new_socket_io_channel, Genode::env()->heap());
Socket_io_channel *socket_io_channel = new Socket_io_channel(socket);
Shared_pointer<Io_channel> io_channel(socket_io_channel, Genode::env()->heap());
_sysio->accept_out.fd = add_io_channel(channel);
/* add new socket to registry */
Socket_descriptor_registry<Socket_io_channel>::instance()->add_io_channel(channel.dynamic_pointer_cast<Socket_io_channel>(),
_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_channel> 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_channel> 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_channel> 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_channel> 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_channel> 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_channel> 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_channel> 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_channel> 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_channel> 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;
}
}

View File

@ -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 <shared_pointer.h>
namespace Noux {
enum { MAX_SOCKET_DESCRIPTORS = 64 };
template<typename T>
class Socket_descriptor_registry
{
private:
struct {
bool allocated;
Shared_pointer<T> io_channel;
} _sds[MAX_SOCKET_DESCRIPTORS];
void _assign_sd(int sd, Shared_pointer<T> &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<T>();
_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<T> 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<T> io_channel_by_sd(int sd) const
{
if (!sd_in_use(sd)) {
PWRN("Socket descriptor %d is not open", sd);
return Shared_pointer<T>();
}
return _sds[sd].io_channel;
}
static Socket_descriptor_registry<T> *instance()
{
static Socket_descriptor_registry<T> _sdr;
return &_sdr;
}
};
};
#endif /* _NOUX__SOCKET_DESCRIPTOR_REGISTRY_H_ */

View File

@ -26,6 +26,8 @@
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
@ -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);
}
};
}