diff --git a/base-linux/include/base/ipc.h b/base-linux/include/base/ipc.h index 1fb3fcd7d6..2fff12b1a7 100644 --- a/base-linux/include/base/ipc.h +++ b/base-linux/include/base/ipc.h @@ -16,50 +16,23 @@ #include -#include - -extern "C" int raw_write_str(const char *str); -extern "C" void wait_for_continue(void); - -#define PRAWW(fmt, ...) \ - do { \ - char str[128]; \ - Genode::snprintf(str, sizeof(str), \ - ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \ - raw_write_str(str); \ - } while (0) - inline void Genode::Ipc_ostream::_marshal_capability(Genode::Native_capability const &cap) { - - PRAWW("_marshal_capability called: local_name=%ld, tid=%ld, socket=%d", - cap.local_name(), cap.dst().tid, cap.dst().socket); - _write_to_buf(cap.local_name()); - _write_to_buf(cap.dst().tid); - if (cap.valid()) { - PRAWW("append_cap"); + if (cap.valid()) _snd_msg->append_cap(cap.dst().socket); - } } inline void Genode::Ipc_istream::_unmarshal_capability(Genode::Native_capability &cap) { long local_name = 0; - long tid = 0; - int socket = -1; - _read_from_buf(local_name); - _read_from_buf(tid); - bool const cap_valid = (tid != 0); - if (cap_valid) - socket = _rcv_msg->read_cap(); - - cap = Native_capability(Cap_dst_policy::Dst(tid, socket), local_name); + int const socket = _rcv_msg->read_cap(); + cap = Native_capability(Cap_dst_policy::Dst(socket), local_name); } #endif /* _INCLUDE__BASE__IPC_H_ */ diff --git a/base-linux/include/base/ipc_msgbuf.h b/base-linux/include/base/ipc_msgbuf.h index e40883a55a..9eea16a4d0 100644 --- a/base-linux/include/base/ipc_msgbuf.h +++ b/base-linux/include/base/ipc_msgbuf.h @@ -91,10 +91,6 @@ namespace Genode { { return index < _used_caps ? _caps[index] : -1; } - - size_t used_size() const { return _used_size; } - - void used_size(size_t used_size) { _used_size = used_size; } }; diff --git a/base-linux/include/base/local_interface.h b/base-linux/include/base/local_interface.h index 8f935e817f..34e5996a75 100644 --- a/base-linux/include/base/local_interface.h +++ b/base-linux/include/base/local_interface.h @@ -56,7 +56,7 @@ namespace Genode { static IF *deref(Capability cap) { /* check if this is a pseudo capability */ - if (cap.dst().tid != 0 || !cap.local_name()) + if (cap.dst().socket != -1 || !cap.local_name()) throw Non_local_capability(); /* diff --git a/base-linux/include/base/native_types.h b/base-linux/include/base/native_types.h index 39c141bc76..303552d36c 100644 --- a/base-linux/include/base/native_types.h +++ b/base-linux/include/base/native_types.h @@ -98,19 +98,17 @@ namespace Genode { { struct Dst { - long tid; /* XXX to be removed once the transition to SCM rights - is completed */ int socket; /** * Default constructor creates invalid destination */ - Dst() : tid(0), socket(-1) { } + Dst() : socket(-1) { } - Dst(long tid, int socket) : tid(tid), socket(socket) { } + explicit Dst(int socket) : socket(socket) { } }; - static bool valid(Dst id) { return id.tid != 0; } + static bool valid(Dst id) { return id.socket != -1; } static Dst invalid() { return Dst(); } static void copy(void* dst, Native_capability_tpl* src); }; @@ -125,7 +123,15 @@ namespace Genode { /** * The connection state is the socket handle of the RPC entrypoint */ - typedef int Native_connection_state; + struct Native_connection_state + { + int server_sd; + int client_sd; + + Native_connection_state() : server_sd(-1), client_sd(-1) { } + }; + + enum { PARENT_SOCKET_HANDLE = 100 }; struct Native_config { diff --git a/base-linux/include/base/platform_env.h b/base-linux/include/base/platform_env.h index 1bdcb17838..54a02b64c1 100644 --- a/base-linux/include/base/platform_env.h +++ b/base-linux/include/base/platform_env.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace Genode { @@ -323,13 +324,12 @@ namespace Genode { Parent_capability _parent_cap() { - long tid = _get_env_ulong("parent_tid"); long local_name = _get_env_ulong("parent_local_name"); /* produce typed capability manually */ typedef Native_capability::Dst Dst; - return reinterpret_cap_cast(Native_capability(Dst(tid, -1), - local_name)); + Dst const dst(PARENT_SOCKET_HANDLE); + return reinterpret_cap_cast(Native_capability(dst, local_name)); } @@ -343,6 +343,7 @@ namespace Genode { Cpu_session_capability _cpu_session_cap; Cpu_session_client _cpu_session_client; Rm_session_mmap _rm_session_mmap; + Pd_session_client _pd_session_client; Heap _heap; public: @@ -358,6 +359,7 @@ namespace Genode { _cpu_session_cap(static_cap_cast(parent()->session("Env::cpu_session", ""))), _cpu_session_client(_cpu_session_cap), _rm_session_mmap(false), + _pd_session_client(static_cap_cast(parent()->session("Env::pd_session", ""))), _heap(&_ram_session_client, &_rm_session_mmap) { } diff --git a/base-linux/src/base/env/debug.cc b/base-linux/src/base/env/debug.cc index d794fc95a1..227da2b661 100644 --- a/base-linux/src/base/env/debug.cc +++ b/base-linux/src/base/env/debug.cc @@ -55,3 +55,6 @@ extern "C" void wait_for_continue(void) lx_syscall(SYS_read, (int)0, buf, sizeof(buf)); #endif /* DEBUG */ } + + +extern "C" int get_pid() { return lx_getpid(); } diff --git a/base-linux/src/base/ipc/ipc.cc b/base-linux/src/base/ipc/ipc.cc index 8fd885c0e4..8c3e037e7d 100644 --- a/base-linux/src/base/ipc/ipc.cc +++ b/base-linux/src/base/ipc/ipc.cc @@ -7,7 +7,6 @@ * The current request message layout is: * * long server_local_name; - * long client_thread_id; * int opcode; * ...payload... * @@ -46,6 +45,14 @@ using namespace Genode; + +Genode::Ep_socket_descriptor_registry *Genode::ep_sd_registry() +{ + static Genode::Ep_socket_descriptor_registry registry; + return ®istry; +} + + /***************** ** Ipc_ostream ** *****************/ @@ -94,7 +101,7 @@ void Ipc_istream::_wait() Ipc_istream::Ipc_istream(Msgbuf_base *rcv_msg) : Ipc_unmarshaller(rcv_msg->buf, rcv_msg->size()), - Native_capability(Dst(lx_gettid(), -1), 0), + Native_capability(Dst(-1), 0), _rcv_msg(rcv_msg) { } @@ -123,10 +130,9 @@ void Ipc_client::_prepare_next_call() void Ipc_client::_call() { - if (Ipc_ostream::_dst.valid()) { - _snd_msg->used_size(_write_offset); - lx_call(Ipc_ostream::_dst.dst().tid, *_snd_msg, *_rcv_msg); - } + if (Ipc_ostream::_dst.valid()) + lx_call(Ipc_ostream::_dst.dst().socket, *_snd_msg, _write_offset, *_rcv_msg); + _prepare_next_call(); } @@ -165,6 +171,15 @@ void Ipc_server::_wait() { _reply_needed = true; + /* + * Block infinitely if called from the main thread. This may happen if the + * main thread calls 'sleep_forever()'. + */ + if (!Thread_base::myself()) { + struct timespec ts = { 1000, 0 }; + for (;;) lx_nanosleep(&ts, 0); + } + try { int const reply_socket = lx_wait(_rcv_cs, *_rcv_msg); @@ -176,11 +191,8 @@ void Ipc_server::_wait() * object, the 'local_name' is meaningless. */ enum { DUMMY_LOCAL_NAME = -1 }; - typedef Native_capability::Dst Dst; - enum { DUMMY_TID = -1 }; - Dst dst(DUMMY_TID, reply_socket); - Ipc_ostream::_dst = Native_capability(dst, DUMMY_LOCAL_NAME); + Ipc_ostream::_dst = Native_capability(Dst(reply_socket), DUMMY_LOCAL_NAME); _prepare_next_reply_wait(); } catch (Blocking_canceled) { } @@ -190,9 +202,8 @@ void Ipc_server::_wait() void Ipc_server::_reply() { try { - _snd_msg->used_size(_write_offset); - lx_reply(Ipc_ostream::_dst.dst().socket, *_snd_msg); - } catch (Ipc_error) { } + lx_reply(Ipc_ostream::_dst.dst().socket, *_snd_msg, _write_offset); } + catch (Ipc_error) { } _prepare_next_reply_wait(); } @@ -201,10 +212,8 @@ void Ipc_server::_reply() void Ipc_server::_reply_wait() { /* when first called, there was no request yet */ - if (_reply_needed) { - _snd_msg->used_size(_write_offset); - lx_reply(Ipc_ostream::_dst.dst().socket, *_snd_msg); - } + if (_reply_needed) + lx_reply(Ipc_ostream::_dst.dst().socket, *_snd_msg, _write_offset); _wait(); } @@ -229,19 +238,14 @@ Ipc_server::Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg) throw Ipc_server_multiple_instance(); } - _rcv_cs = lx_server_socket(Thread_base::myself()); - if (_rcv_cs < 0) { - PRAW("lx_server_socket failed (error %d)", _rcv_cs); - struct Ipc_socket_creation_failed { }; - throw Ipc_socket_creation_failed(); - } + _rcv_cs = lx_server_socket_pair(Thread_base::myself()); if (thread) thread->tid().is_ipc_server = true; /* override capability initialization performed by 'Ipc_istream' */ *static_cast(this) = - Native_capability(Native_capability::Dst(lx_gettid(), _rcv_cs), 0); + Native_capability(Native_capability::Dst(_rcv_cs.client_sd), 0); _prepare_next_reply_wait(); } diff --git a/base-linux/src/base/process/process.cc b/base-linux/src/base/process/process.cc index 07f94ec2c6..e6397936cb 100644 --- a/base-linux/src/base/process/process.cc +++ b/base-linux/src/base/process/process.cc @@ -30,18 +30,22 @@ Dataspace_capability Process::_dynamic_linker_cap; /** * Argument frame for passing 'execve' paremeters through 'clone' */ -struct execve_args { - const char *filename; - char *const*argv; - char *const*envp; +struct Execve_args +{ + const char *filename; + char *const *argv; + char *const *envp; + int parent_sd; }; /** * Startup code of the new child process */ -static int _exec_child(struct execve_args *arg) +static int _exec_child(Execve_args *arg) { + lx_dup2(arg->parent_sd, PARENT_SOCKET_HANDLE); + return lx_execve(arg->filename, arg->argv, arg->envp); } @@ -67,6 +71,7 @@ static const char *get_env(const char *key) return ""; } + /** * Check for dynamic ELF header */ @@ -115,8 +120,6 @@ const char *Process::_priv_pd_args(Parent_capability parent_cap, /* pass parent capability as environment variable to the child */ enum { ENV_STR_LEN = 256 }; static char envbuf[5][ENV_STR_LEN]; - Genode::snprintf(envbuf[0], ENV_STR_LEN, "parent_tid=%ld", - parent_cap.dst().tid); Genode::snprintf(envbuf[1], ENV_STR_LEN, "parent_local_name=%lu", parent_cap.local_name()); Genode::snprintf(envbuf[2], ENV_STR_LEN, "DISPLAY=%s", @@ -162,16 +165,11 @@ const char *Process::_priv_pd_args(Parent_capability parent_cap, enum { STACK_SIZE = 4096 }; static char stack[STACK_SIZE]; /* initial stack used by the child until calling 'execve' */ - /* * Argument frame as passed to 'clone'. Because, we can only pass a single * pointer, all arguments are embedded within the 'execve_args' struct. */ - struct execve_args arg = { - fname.buf, - argv, - env - }; + Execve_args arg = { fname.buf, argv, env, parent_cap.dst().socket }; pid_t pid = lx_create_process((int (*)(void *))_exec_child, stack + STACK_SIZE - sizeof(umword_t), &arg); diff --git a/base-linux/src/platform/linux_socket.h b/base-linux/src/platform/linux_socket.h index b6de58c93e..735eaf6f61 100644 --- a/base-linux/src/platform/linux_socket.h +++ b/base-linux/src/platform/linux_socket.h @@ -1,6 +1,7 @@ /* * \brief Linux socket utilities * \author Christian Helmuth + * \author Norman Feske * \date 2012-01-17 * * We create one socket under lx_rpath() for each 'Ipc_server'. The naming is @@ -39,31 +40,154 @@ extern "C" int raw_write_str(const char *str); } while (0) -/** - * Utility: Create socket address for server entrypoint atthread ID +/****************************** + ** File-descriptor registry ** + ******************************/ + +/* + * We use the name of the Unix-domain socket as key to uniquely identify + * entrypoints. When receiving a socket descriptor as IPC payload, we first + * lookup the corresponding entrypoint ID. If we already possess a socket + * descriptor pointing to the same entrypoint, we close the received one and + * use the already known descriptor instead. */ -static void lx_create_server_addr(sockaddr_un *addr, long thread_id) + +namespace Genode { - addr->sun_family = AF_UNIX; - Genode::snprintf(addr->sun_path, sizeof(addr->sun_path), "%s/ep-%ld", - lx_rpath(), thread_id); + template + class Socket_descriptor_registry; + + typedef Socket_descriptor_registry<100> Ep_socket_descriptor_registry; + + /** + * Return singleton instance of registry for tracking entrypoint sockets + */ + Ep_socket_descriptor_registry *ep_sd_registry(); } +template +class Genode::Socket_descriptor_registry +{ + public: + + class Limit_reached { }; + class Aliased_global_id { }; + + private: + + struct Entry + { + int fd; + int global_id; + + /** + * Default constructor creates empty entry + */ + Entry() : fd(-1), global_id(-1) { } + + Entry(int fd, int global_id) : fd(fd), global_id(global_id) { } + + bool is_free() const { return fd == -1; } + }; + + Entry _entries[MAX_FDS]; + + Genode::Lock mutable _lock; + + Entry &_find_free_entry() + { + for (unsigned i = 0; i < MAX_FDS; i++) + if (_entries[i].is_free()) + return _entries[i]; + + throw Limit_reached(); + } + + bool _is_registered(int global_id) const + { + for (unsigned i = 0; i < MAX_FDS; i++) + if (_entries[i].global_id == global_id) + return true; + + return false; + } + + public: + + /** + * Register association of socket descriptor and its corresponding ID + * + * \throw Limit_reached + * \throw Aliased_global_id if global ID is already registered + */ + void associate(int sd, int global_id) + { + Genode::Lock::Guard guard(_lock); + + /* ignore invalid capabilities */ + if (sd == -1 || global_id == -1) + return; + + /* + * Check for potential aliasing + * + * We allow any global ID to be present in the registry only once. + */ + if (_is_registered(global_id)) { + PRAW("attempted to register global ID %d twice", global_id); + throw Aliased_global_id(); + } + + Entry &entry = _find_free_entry(); + entry = Entry(sd, global_id); + } + + /** + * Lookup file descriptor that belongs to specified global ID + * + * \return file descriptor or -1 if lookup failed + */ + int lookup_fd_by_global_id(int global_id) const + { + Genode::Lock::Guard guard(_lock); + + for (unsigned i = 0; i < MAX_FDS; i++) + if (_entries[i].global_id == global_id) + return _entries[i].fd; + + return -1; + } +}; + + /** - * Utility: Return thread ID to which the given socket is bound - * - * \return -1 if the socket is not bound to an entrypoint + * Utility: Create socket address for server entrypoint at thread ID */ -static int lookup_tid_by_socket(int sd) +struct Uds_addr : sockaddr_un +{ + Uds_addr(long thread_id) + { + sun_family = AF_UNIX; + Genode::snprintf(sun_path, sizeof(sun_path), "%s/ep-%ld", + lx_rpath(), thread_id); + } +}; + + + +/** + * Utility: Return thread ID to which the given socket is directed to + * + * \return -1 if the socket is pointing to a valid entrypoint + */ +static int lookup_tid_by_client_socket(int sd) { sockaddr_un name; socklen_t name_len = sizeof(name); - int ret = lx_getsockname(sd, (sockaddr *)&name, &name_len); - if (ret < 0) { - PRAW("Error: lx_getsockname returned %d", ret); + int ret = lx_getpeername(sd, (sockaddr *)&name, &name_len); + if (ret < 0) return -1; - } /* * The socket name has the form '/ep-'. Hence, to determine the @@ -115,18 +239,10 @@ namespace { public: - Message(long server_thread_id = -1) : _num_sds(0) + Message(void *buffer, size_t buffer_len) : _num_sds(0) { memset(&_msg, 0, sizeof(_msg)); - if (server_thread_id != -1) { - /* initialize receiver */ - lx_create_server_addr(&_addr, server_thread_id); - - _msg.msg_name = &_addr; - _msg.msg_namelen = sizeof(_addr); - } - /* initialize control message */ struct cmsghdr *cmsg; @@ -138,12 +254,7 @@ namespace { cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; _msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */ - } - msghdr * msg() { return &_msg; } - - void buffer(void *buffer, size_t buffer_len) - { /* initialize iovec */ _msg.msg_iov = &_iovec; _msg.msg_iovlen = 1; @@ -152,6 +263,8 @@ namespace { _iovec.iov_len = buffer_len; } + msghdr * msg() { return &_msg; } + void marshal_socket(int sd) { *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd; @@ -170,17 +283,7 @@ namespace { _msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */ } - int unmarshal_socket() - { - int ret = *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds); - - _num_sds++; - - return ret; - } - - /* XXX only for debugging */ - int socket_at_index(int index) + int socket_at_index(int index) const { return *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index); } @@ -200,45 +303,107 @@ namespace { /** - * Utility: Get server socket for given thread + * Utility: Extract socket desriptors from SCM message into 'Genode::Msgbuf' */ -static int lx_server_socket(Genode::Thread_base *thread) +static void extract_sds_from_message(unsigned start_index, Message const &msg, + Genode::Msgbuf_base &buf) { - int sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (sd < 0) - return sd; + buf.reset_caps(); + + /* start at offset 1 to skip the reply channel */ + for (unsigned i = start_index; i < msg.num_sockets(); i++) { + + int const sd = msg.socket_at_index(i); + int const id = lookup_tid_by_client_socket(sd); + int const existing_sd = Genode::ep_sd_registry()->lookup_fd_by_global_id(id); + + if (existing_sd >= 0) { + lx_close(sd); + buf.append_cap(existing_sd); + } else { + Genode::ep_sd_registry()->associate(sd, id); + buf.append_cap(sd); + } + } +} + + +class Server_socket_failed { }; +class Client_socket_failed { }; +class Bind_failed { }; +class Connect_failed { }; + + +/** + * Utility: Create named socket pair for given thread + * + * \throw Server_socket_failed + * \throw Client_socket_failed + * \throw Bind_failed + * \throw Connect_failed + */ +static Genode::Native_connection_state lx_server_socket_pair(Genode::Thread_base *thread) +{ + Genode::Native_connection_state ncs; /* - * Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need - * for binding. + * Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for + * binding. */ if (!thread) - return sd; + return ncs; - sockaddr_un addr; - lx_create_server_addr(&addr, thread->tid().tid); + Uds_addr addr(thread->tid().tid); + + /* + * Create server-side socket + */ + ncs.server_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (ncs.server_sd < 0) { + PRAW("Error: Could not create server-side socket (ret=%d)", ncs.server_sd); + throw Server_socket_failed(); + } /* make sure bind succeeds */ lx_unlink(addr.sun_path); - int const bind_ret = lx_bind(sd, (sockaddr *)&addr, sizeof(addr)); - if (bind_ret < 0) - return bind_ret; + int const bind_ret = lx_bind(ncs.server_sd, (sockaddr *)&addr, sizeof(addr)); + if (bind_ret < 0) { + PRAW("Error: Could not bind server socket (ret=%d)", bind_ret); + throw Bind_failed(); + } - return sd; + /* + * Create client-side socket + */ + ncs.client_sd = lx_socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (ncs.client_sd < 0) { + PRAW("Error: Could not create client-side socket (ret=%d)", ncs.client_sd); + throw Client_socket_failed(); + } + + int const conn_ret = lx_connect(ncs.client_sd, (sockaddr *)&addr, sizeof(addr)); + if (conn_ret < 0) { + PRAW("Error: Could not connect client-side socket (ret=%d)", conn_ret); + throw Connect_failed(); + } + + int const tid = lookup_tid_by_client_socket(ncs.client_sd); + Genode::ep_sd_registry()->associate(ncs.client_sd, tid); + + return ncs; } /** * Utility: Send request to server and wait for reply */ -static void lx_call(long thread_id, - Genode::Msgbuf_base &send_msgbuf, +static void lx_call(int dst_sd, + Genode::Msgbuf_base &send_msgbuf, size_t send_msg_len, Genode::Msgbuf_base &recv_msgbuf) { int ret; - - Message send_msg(thread_id); + Message send_msg(send_msgbuf.buf, send_msg_len); /* create reply channel */ enum { LOCAL_SOCKET = 0, REMOTE_SOCKET = 1 }; @@ -247,7 +412,6 @@ static void lx_call(long thread_id, ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, reply_channel); if (ret < 0) { PRAW("lx_socketpair failed with %d", ret); - /* XXX */ wait_for_continue(); throw Genode::Ipc_error(); } @@ -257,54 +421,27 @@ static void lx_call(long thread_id, send_msg.marshal_socket(reply_channel[REMOTE_SOCKET]); /* marshal capabilities contained in 'send_msgbuf' */ - if (send_msgbuf.used_caps() > 0) - PRAW("lx_call: marshal %d caps:", send_msgbuf.used_caps()); + for (unsigned i = 0; i < send_msgbuf.used_caps(); i++) + send_msg.marshal_socket(send_msgbuf.cap(i)); - for (unsigned i = 0; i < send_msgbuf.used_caps(); i++) { - PRAW(" sd[%d]: %d", i, send_msgbuf.cap(i)); - send_msg.marshal_socket(lx_dup(send_msgbuf.cap(i))); - } - - send_msg.buffer(send_msgbuf.buf, send_msgbuf.used_size()); - - /* - * The socket argument is not actually used. It just needs to match the - * socket type. - */ - ret = lx_sendmsg(reply_channel[LOCAL_SOCKET], send_msg.msg(), 0); + ret = lx_sendmsg(dst_sd, send_msg.msg(), 0); if (ret < 0) { PRAW("lx_sendmsg failed with %d in lx_call()", ret); - /* XXX */ wait_for_continue(); throw Genode::Ipc_error(); } - Message recv_msg; - recv_msg.accept_sockets(Message::MAX_SDS_PER_MSG); + /* receive reply */ - recv_msg.buffer(recv_msgbuf.buf, recv_msgbuf.size()); + Message recv_msg(recv_msgbuf.buf, recv_msgbuf.size()); + recv_msg.accept_sockets(Message::MAX_SDS_PER_MSG); ret = lx_recvmsg(reply_channel[LOCAL_SOCKET], recv_msg.msg(), 0); if (ret < 0) { PRAW("lx_recvmsg failed with %d in lx_call()", ret); - /* XXX */ wait_for_continue(); throw Genode::Ipc_error(); } - /* - * 'lx_recvmsg()' returns the number of bytes received. Remember this value - * in 'Genode::Msgbuf_base' - * - * XXX revisit whether we really need this information - */ - recv_msgbuf.used_size(ret); - - if (recv_msg.num_sockets() > 0) { - PRAW("lx_call: got %d sockets in reply", recv_msg.num_sockets()); - for (unsigned i = 0; i < recv_msg.num_sockets(); i++) { - PRAW(" sd[%d]: %d", i, recv_msg.socket_at_index(i)); - lx_close(recv_msg.socket_at_index(i)); - } - } + extract_sds_from_message(0, recv_msg, recv_msgbuf); /* destroy reply channel */ lx_close(reply_channel[LOCAL_SOCKET]); @@ -320,44 +457,19 @@ static void lx_call(long thread_id, static int lx_wait(Genode::Native_connection_state &cs, Genode::Msgbuf_base &recv_msgbuf) { - Message msg; + Message msg(recv_msgbuf.buf, recv_msgbuf.size()); msg.accept_sockets(Message::MAX_SDS_PER_MSG); - msg.buffer(recv_msgbuf.buf, recv_msgbuf.size()); - int ret = lx_recvmsg(cs, msg.msg(), 0); + int ret = lx_recvmsg(cs.server_sd, msg.msg(), 0); if (ret < 0) { - PRAW("lx_recvmsg failed with %d in lx_wait()", ret); - /* XXX */ wait_for_continue(); + PRAW("lx_recvmsg failed with %d in lx_wait(), sd=%d", ret, cs.server_sd); throw Genode::Ipc_error(); } - /* - * 'lx_recvmsg()' returned message size, keep it in 'recv_msgbuf'. - * - * XXX revisit whether this information is actually needed. - */ - recv_msgbuf.used_size(ret); + int const reply_socket = msg.socket_at_index(0); - - if (msg.num_sockets() > 1) { - PRAW("lx_wait: got %d sockets from wait", msg.num_sockets()); - for (unsigned i = 0; i < msg.num_sockets(); i++) { - - int tid = (i > 0) ? lookup_tid_by_socket(msg.socket_at_index(i)) : -1; - PRAW(" sd[%d]: %d, tid=%d", i, msg.socket_at_index(i), tid); - - /* don't close reply channel */ - if (i > 0) - lx_close(msg.socket_at_index(i)); - } - } - - int reply_socket = msg.unmarshal_socket(); - - /* - * Copy-out additional sds from msg to recv_msgbuf - */ + extract_sds_from_message(1, msg, recv_msgbuf); return reply_socket; } @@ -367,11 +479,16 @@ static int lx_wait(Genode::Native_connection_state &cs, * Utility: Send reply to client */ static void lx_reply(int reply_socket, - Genode::Msgbuf_base &send_msgbuf) + Genode::Msgbuf_base &send_msgbuf, + size_t msg_len) { - Message msg; + Message msg(send_msgbuf.buf, msg_len); - msg.buffer(send_msgbuf.buf, send_msgbuf.used_size()); + /* + * Marshall capabilities to be transferred to the client + */ + for (unsigned i = 0; i < send_msgbuf.used_caps(); i++) + msg.marshal_socket(send_msgbuf.cap(i)); int ret = lx_sendmsg(reply_socket, msg.msg(), 0); if (ret < 0) diff --git a/base-linux/src/platform/linux_syscalls.h b/base-linux/src/platform/linux_syscalls.h index f2382d26af..0b824861c1 100644 --- a/base-linux/src/platform/linux_syscalls.h +++ b/base-linux/src/platform/linux_syscalls.h @@ -70,6 +70,12 @@ inline int lx_dup(int fd) } +inline int lx_dup2(int fd, int to) +{ + return lx_syscall(SYS_dup2, fd, to); +} + + inline int lx_unlink(const char *fname) { return lx_syscall(SYS_unlink, fname); @@ -113,6 +119,14 @@ inline int lx_bind(int sockfd, const struct sockaddr *addr, } +inline int lx_connect(int sockfd, const struct sockaddr *serv_addr, + socklen_t addrlen) +{ + unsigned long args[3] = { sockfd, (unsigned long)serv_addr, addrlen }; + return lx_socketcall(SYS_CONNECT, args); +} + + inline int lx_sendmsg(int sockfd, const struct msghdr *msg, int flags) { unsigned long args[3] = { sockfd, (unsigned long)msg, flags }; @@ -127,10 +141,10 @@ inline int lx_recvmsg(int sockfd, struct msghdr *msg, int flags) } -inline int lx_getsockname(int sockfd, struct sockaddr *name, socklen_t *namelen) +inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen) { unsigned long args[3] = { sockfd, (unsigned long)name, (unsigned long)namelen }; - return lx_socketcall(SYS_GETSOCKNAME, args); + return lx_socketcall(SYS_GETPEERNAME, args); } #else @@ -140,9 +154,23 @@ inline int lx_socket(int domain, int type, int protocol) return lx_syscall(SYS_socket, domain, type, protocol); } -inline int lx_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +inline int lx_bind(int sockfd, const struct sockaddr *addr, + socklen_t addrlen) { - return lx_syscall(SYS_getsockname, s, name, namelen); + return lx_syscall(SYS_bind, sockfd, addr, addrlen); +} + + +inline int lx_connect(int sockfd, const struct sockaddr *serv_addr, + socklen_t addrlen) +{ + return lx_syscall(SYS_connect, sockfd, serv_addr, addrlen); +} + + +inline int lx_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ + return lx_syscall(SYS_getpeername, s, name, namelen); } /* TODO add missing socket system calls */