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 */