mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
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:
parent
08bd41b1ec
commit
082d8d6623
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user