mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-09 04:15:52 +00:00
Linux: cleanup system-call bindings
This patch simplifies the system call bindings. The common syscall bindings in 'src/platform/' have been reduced to the syscalls needed by non-core programs. The additional syscalls that are needed solely by core have been moved to 'src/core/include/core_linux_syscalls.h'. Furthermore, the resource path is not used outside of core anymore. Hence, we could get rid of the rpath library. The resource-path code has been moved to 'src/core/include/resource_path.h'. The IPC-related parts of 'src/platform' have been moved to the IPC library. So there is now a clean separation between low-level syscall bindings (in 'src/platform') and higher-level code. The code for the socket-descriptor registry is now located in the 'src/base/ipc/socket_descriptor_registry.h' header. The interface is separated from 'ipc.cc' because core needs to access the registry from outside the ipc library.
This commit is contained in:
parent
371b8fd12d
commit
de69ee2e66
@ -1,5 +1,6 @@
|
||||
REQUIRES = linux
|
||||
SRC_CC = ipc.cc
|
||||
LIBS = syscall rpath cap_copy
|
||||
LIBS = syscall cap_copy
|
||||
INC_DIR += $(REP_DIR)/src/base/ipc
|
||||
|
||||
vpath ipc.cc $(REP_DIR)/src/base/ipc
|
||||
|
@ -1,6 +0,0 @@
|
||||
REQUIRES = linux
|
||||
SRC_CC = linux_rpath.cc
|
||||
LIBS = syscall
|
||||
|
||||
vpath linux_rpath.cc $(REP_DIR)/src/platform
|
||||
|
@ -34,14 +34,21 @@
|
||||
#include <base/env.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
/* local includes */
|
||||
#include <socket_descriptor_registry.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_socket.h>
|
||||
#include <linux_syscalls.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/******************************
|
||||
** File-descriptor registry **
|
||||
******************************/
|
||||
|
||||
Genode::Ep_socket_descriptor_registry *Genode::ep_sd_registry()
|
||||
{
|
||||
@ -50,6 +57,275 @@ Genode::Ep_socket_descriptor_registry *Genode::ep_sd_registry()
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
** Communication over Unix-domain sockets **
|
||||
********************************************/
|
||||
|
||||
/**
|
||||
* 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_getpeername(sd, (sockaddr *)&name, &name_len);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
struct Prefix_len
|
||||
{
|
||||
size_t const len;
|
||||
|
||||
static int _init_len(char const *s)
|
||||
{
|
||||
char const * const pattern = "/ep-";
|
||||
static size_t const pattern_len = Genode::strlen(pattern);
|
||||
|
||||
for (size_t i = 0; Genode::strlen(s + i) >= pattern_len; i++)
|
||||
if (Genode::strcmp(s + i, pattern, pattern_len) == 0)
|
||||
return i + pattern_len;
|
||||
|
||||
struct Unexpected_rpath_prefix { };
|
||||
throw Unexpected_rpath_prefix();
|
||||
}
|
||||
|
||||
Prefix_len(char const *s) : len(_init_len(s)) { }
|
||||
};
|
||||
|
||||
/*
|
||||
* The name of the Unix-domain socket has the form <rpath>-<uid>/ep-<tid>.
|
||||
* We are only interested in the <tid> part. Hence, we determine the length
|
||||
* of the <rpath>-<uid>/ep- portion only once and keep it in a static
|
||||
* variable.
|
||||
*/
|
||||
static Prefix_len prefix_len(name.sun_path);
|
||||
|
||||
unsigned tid = 0;
|
||||
if (Genode::ascii_to(name.sun_path + prefix_len.len, &tid) == 0) {
|
||||
PRAW("Error: could not parse tid number");
|
||||
return -1;
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Message object encapsulating data for sendmsg/recvmsg
|
||||
*/
|
||||
struct Message
|
||||
{
|
||||
public:
|
||||
|
||||
enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG };
|
||||
|
||||
private:
|
||||
|
||||
msghdr _msg;
|
||||
sockaddr_un _addr;
|
||||
iovec _iovec;
|
||||
char _cmsg_buf[CMSG_SPACE(MAX_SDS_PER_MSG*sizeof(int))];
|
||||
|
||||
unsigned _num_sds;
|
||||
|
||||
public:
|
||||
|
||||
Message(void *buffer, size_t buffer_len) : _num_sds(0)
|
||||
{
|
||||
Genode::memset(&_msg, 0, sizeof(_msg));
|
||||
|
||||
/* initialize control message */
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
_msg.msg_control = _cmsg_buf;
|
||||
_msg.msg_controllen = sizeof(_cmsg_buf); /* buffer space available */
|
||||
_msg.msg_flags |= MSG_CMSG_CLOEXEC;
|
||||
cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(0);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
|
||||
/* initialize iovec */
|
||||
_msg.msg_iov = &_iovec;
|
||||
_msg.msg_iovlen = 1;
|
||||
|
||||
_iovec.iov_base = buffer;
|
||||
_iovec.iov_len = buffer_len;
|
||||
}
|
||||
|
||||
msghdr * msg() { return &_msg; }
|
||||
|
||||
void marshal_socket(int sd)
|
||||
{
|
||||
*((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd;
|
||||
|
||||
_num_sds++;
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(_num_sds*sizeof(int));
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
}
|
||||
|
||||
void accept_sockets(int num_sds)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(num_sds*sizeof(int));
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
}
|
||||
|
||||
int socket_at_index(int index) const
|
||||
{
|
||||
return *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index);
|
||||
}
|
||||
|
||||
unsigned num_sockets() const
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
|
||||
if (!cmsg)
|
||||
return 0;
|
||||
|
||||
return (cmsg->cmsg_len - CMSG_ALIGN(sizeof(cmsghdr)))/sizeof(int);
|
||||
}
|
||||
};
|
||||
|
||||
} /* unnamed namespace */
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Extract socket desriptors from SCM message into 'Genode::Msgbuf'
|
||||
*/
|
||||
static void extract_sds_from_message(unsigned start_index, Message const &msg,
|
||||
Genode::Msgbuf_base &buf)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send request to server and wait for reply
|
||||
*/
|
||||
static inline 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(send_msgbuf.buf, send_msg_len);
|
||||
|
||||
/* create reply channel */
|
||||
enum { LOCAL_SOCKET = 0, REMOTE_SOCKET = 1 };
|
||||
int reply_channel[2];
|
||||
|
||||
ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, reply_channel);
|
||||
if (ret < 0) {
|
||||
PRAW("lx_socketpair failed with %d", ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
/* assemble message */
|
||||
|
||||
/* marshal reply capability */
|
||||
send_msg.marshal_socket(reply_channel[REMOTE_SOCKET]);
|
||||
|
||||
/* marshal capabilities contained in 'send_msgbuf' */
|
||||
for (unsigned i = 0; i < send_msgbuf.used_caps(); i++)
|
||||
send_msg.marshal_socket(send_msgbuf.cap(i));
|
||||
|
||||
ret = lx_sendmsg(dst_sd, send_msg.msg(), 0);
|
||||
if (ret < 0) {
|
||||
PRAW("[%d] lx_sendmsg to sd %d failed with %d in lx_call()",
|
||||
lx_getpid(), dst_sd, ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
/* receive reply */
|
||||
|
||||
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("[%d] lx_recvmsg failed with %d in lx_call()", lx_getpid(), ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
extract_sds_from_message(0, recv_msg, recv_msgbuf);
|
||||
|
||||
/* destroy reply channel */
|
||||
lx_close(reply_channel[LOCAL_SOCKET]);
|
||||
lx_close(reply_channel[REMOTE_SOCKET]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* for request from client
|
||||
*
|
||||
* \return socket descriptor of reply capability
|
||||
*/
|
||||
static inline int lx_wait(Genode::Native_connection_state &cs,
|
||||
Genode::Msgbuf_base &recv_msgbuf)
|
||||
{
|
||||
Message msg(recv_msgbuf.buf, recv_msgbuf.size());
|
||||
|
||||
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
|
||||
|
||||
int ret = lx_recvmsg(cs.server_sd, msg.msg(), 0);
|
||||
if (ret < 0) {
|
||||
PRAW("lx_recvmsg failed with %d in lx_wait(), sd=%d", ret, cs.server_sd);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
int const reply_socket = msg.socket_at_index(0);
|
||||
|
||||
extract_sds_from_message(1, msg, recv_msgbuf);
|
||||
|
||||
return reply_socket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send reply to client
|
||||
*/
|
||||
static inline void lx_reply(int reply_socket,
|
||||
Genode::Msgbuf_base &send_msgbuf,
|
||||
size_t msg_len)
|
||||
{
|
||||
Message msg(send_msgbuf.buf, msg_len);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
PRAW("lx_sendmsg failed with %d in lx_reply()", ret);
|
||||
|
||||
lx_close(reply_socket);
|
||||
}
|
||||
|
||||
|
||||
/*****************
|
||||
** Ipc_ostream **
|
||||
*****************/
|
||||
|
132
base-linux/src/base/ipc/socket_descriptor_registry.h
Normal file
132
base-linux/src/base/ipc/socket_descriptor_registry.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* \brief Linux-specific socket-descriptor registry
|
||||
* \author Norman Feske
|
||||
* \date 2012-07-26
|
||||
*
|
||||
* We use the names of Unix-domain sockets as keys 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 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 _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_
|
||||
#define _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_
|
||||
|
||||
#include <base/lock.h>
|
||||
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
template <unsigned MAX_FDS>
|
||||
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 <unsigned MAX_FDS>
|
||||
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))
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_ */
|
@ -63,7 +63,7 @@ extern char **lx_environ;
|
||||
*/
|
||||
static const char *get_env(const char *key)
|
||||
{
|
||||
Genode::size_t key_len = strlen(key);
|
||||
Genode::size_t key_len = Genode::strlen(key);
|
||||
for (char **curr = lx_environ; curr && *curr; curr++)
|
||||
if ((Genode::strcmp(*curr, key, key_len) == 0) && (*curr)[key_len] == '=')
|
||||
return (const char *)(*curr + key_len + 1);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <cpu_session_component.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_socket.h>
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
131
base-linux/src/core/include/core_linux_syscalls.h
Normal file
131
base-linux/src/core/include/core_linux_syscalls.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* \brief Linux system calls that are used in core only
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_
|
||||
#define _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_
|
||||
|
||||
/* basic Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** Functions used by core's ram-session support code **
|
||||
*******************************************************/
|
||||
|
||||
inline int lx_mkdir(char const *pathname, mode_t mode)
|
||||
{
|
||||
return lx_syscall(SYS_mkdir, pathname, mode);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_ftruncate(int fd, unsigned long length)
|
||||
{
|
||||
return lx_syscall(SYS_ftruncate, fd, length);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_unlink(const char *fname)
|
||||
{
|
||||
return lx_syscall(SYS_unlink, fname);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** Functions used by core's rom-session support code **
|
||||
*******************************************************/
|
||||
|
||||
inline int lx_open(const char *pathname, int flags, mode_t mode = 0)
|
||||
{
|
||||
return lx_syscall(SYS_open, pathname, flags, mode);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_stat(const char *path, struct stat64 *buf)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return lx_syscall(SYS_stat, path, buf);
|
||||
#else
|
||||
return lx_syscall(SYS_stat64, path, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
** Process creation and destruction **
|
||||
**************************************/
|
||||
|
||||
/**
|
||||
* Send signal to process
|
||||
*
|
||||
* This function is used by core to kill processes.
|
||||
*/
|
||||
inline int lx_kill(int pid, int signal)
|
||||
{
|
||||
return lx_syscall(SYS_kill, pid, signal);
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
** Communication over Unix-domain sockets **
|
||||
********************************************/
|
||||
|
||||
#ifdef SYS_socketcall
|
||||
|
||||
inline int lx_socket(int domain, int type, int protocol)
|
||||
{
|
||||
unsigned long args[3] = { domain, type, protocol };
|
||||
return lx_socketcall(SYS_SOCKET, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_bind(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
unsigned long args[3] = { sockfd, (unsigned long)addr, addrlen };
|
||||
return lx_socketcall(SYS_BIND, args);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline int lx_socket(int domain, int type, int protocol)
|
||||
{
|
||||
return lx_syscall(SYS_socket, domain, type, protocol);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_bind(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#endif /* SYS_socketcall */
|
||||
|
||||
|
||||
#endif /* _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_ */
|
44
base-linux/src/core/include/resource_path.h
Normal file
44
base-linux/src/core/include/resource_path.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* \brief Genode resource path
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 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 _CORE__INCLUDE__RPATH_H_
|
||||
#define _CORE__INCLUDE__RPATH_H_
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/**
|
||||
* Return resource path for Genode
|
||||
*
|
||||
* Genode creates files for dataspaces and endpoints under in this directory.
|
||||
*/
|
||||
static inline char const *resource_path()
|
||||
{
|
||||
struct Resource_path
|
||||
{
|
||||
char string[32];
|
||||
|
||||
Resource_path()
|
||||
{
|
||||
Genode::snprintf(string, sizeof(string), "/tmp/genode-%d", lx_getuid());
|
||||
}
|
||||
};
|
||||
|
||||
static Resource_path path;
|
||||
return path.string;
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__RPATH_H_ */
|
107
base-linux/src/core/include/server_socket_pair.h
Normal file
107
base-linux/src/core/include/server_socket_pair.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* \brief Support for communication over Unix domain sockets
|
||||
* \author Norman Feske
|
||||
* \date 2012-08-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_
|
||||
#define _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <core_linux_syscalls.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
/* include from 'src/base/ipc' */
|
||||
#include <socket_descriptor_registry.h>
|
||||
|
||||
/* core-local includes */
|
||||
#include <resource_path.h>
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Create socket address for server entrypoint at thread ID
|
||||
*/
|
||||
struct Uds_addr : sockaddr_un
|
||||
{
|
||||
Uds_addr(long thread_id)
|
||||
{
|
||||
sun_family = AF_UNIX;
|
||||
Genode::snprintf(sun_path, sizeof(sun_path), "%s/ep-%ld",
|
||||
resource_path(), thread_id);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Create named socket pair for given unique ID
|
||||
*/
|
||||
static inline Genode::Native_connection_state create_server_socket_pair(long id)
|
||||
{
|
||||
Genode::Native_connection_state ncs;
|
||||
|
||||
/*
|
||||
* Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for
|
||||
* binding.
|
||||
*/
|
||||
if (id == -1)
|
||||
return ncs;
|
||||
|
||||
Uds_addr addr(id);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
class Server_socket_failed { };
|
||||
throw Server_socket_failed();
|
||||
}
|
||||
|
||||
/* make sure bind succeeds */
|
||||
lx_unlink(addr.sun_path);
|
||||
|
||||
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);
|
||||
class Bind_failed { };
|
||||
throw Bind_failed();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
class Client_socket_failed { };
|
||||
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);
|
||||
class Connect_failed { };
|
||||
throw Connect_failed();
|
||||
}
|
||||
|
||||
Genode::ep_sd_registry()->associate(ncs.client_sd, id);
|
||||
|
||||
/*
|
||||
* Wipe Unix domain socket from the file system. It will live as long as
|
||||
* there exist references to it in the form of file descriptors.
|
||||
*/
|
||||
lx_unlink(addr.sun_path);
|
||||
|
||||
return ncs;
|
||||
}
|
||||
|
||||
#endif /* _CORE__INCLUDE__SERVER_SOCKET_PAIR_H_ */
|
@ -20,7 +20,7 @@
|
||||
#include <pd_session_component.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_syscalls.h>
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
@ -17,11 +17,10 @@
|
||||
/* local includes */
|
||||
#include "platform.h"
|
||||
#include "core_env.h"
|
||||
#include "server_socket_pair.h"
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_socket.h>
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_rpath.h>
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
@ -44,7 +43,7 @@ Platform::Platform()
|
||||
lx_sigaction(2, signal_handler);
|
||||
|
||||
/* create resource directory under /tmp */
|
||||
lx_mkdir(lx_rpath(), S_IRWXU);
|
||||
lx_mkdir(resource_path(), S_IRWXU);
|
||||
|
||||
_ram_alloc.add_range((addr_t)_some_mem, sizeof(_some_mem));
|
||||
}
|
||||
@ -57,6 +56,7 @@ void Platform::wait_for_exit()
|
||||
catch (Blocking_canceled) { };
|
||||
}
|
||||
|
||||
|
||||
void Core_parent::exit(int exit_value)
|
||||
{
|
||||
lx_exit_group(exit_value);
|
||||
@ -71,7 +71,7 @@ namespace Genode {
|
||||
|
||||
Native_connection_state server_socket_pair()
|
||||
{
|
||||
return lx_server_socket_pair(Thread_base::myself()->tid().tid);
|
||||
return create_server_socket_pair(Thread_base::myself()->tid().tid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,7 @@
|
||||
|
||||
/* local includes */
|
||||
#include "platform_thread.h"
|
||||
|
||||
/* Linux syscall helper */
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_socket.h>
|
||||
#include "server_socket_pair.h"
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
@ -59,7 +56,7 @@ int Platform_thread::client_sd()
|
||||
{
|
||||
/* construct socket pair on first call */
|
||||
if (_ncs.client_sd == -1)
|
||||
_ncs = lx_server_socket_pair(_tid);
|
||||
_ncs = create_server_socket_pair(_tid);
|
||||
|
||||
return _ncs.client_sd;
|
||||
}
|
||||
|
@ -18,11 +18,11 @@
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/* local includes */
|
||||
#include "ram_session_component.h"
|
||||
#include <ram_session_component.h>
|
||||
#include <resource_path.h>
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_rpath.h>
|
||||
#include <core_linux_syscalls.h>
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
@ -34,8 +34,8 @@ void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
|
||||
{
|
||||
char fname[Linux_dataspace::FNAME_LEN];
|
||||
|
||||
/* create file using a unique file name in 'lx_rpath' */
|
||||
snprintf(fname, sizeof(fname), "%s/ds-%d", lx_rpath(), ram_ds_cnt++);
|
||||
/* create file using a unique file name in the resource path */
|
||||
snprintf(fname, sizeof(fname), "%s/ds-%d", resource_path(), ram_ds_cnt++);
|
||||
lx_unlink(fname);
|
||||
int const fd = lx_open(fname, O_CREAT|O_RDWR|O_TRUNC|LX_O_CLOEXEC, S_IRWXU);
|
||||
lx_ftruncate(fd, ds->size());
|
||||
|
@ -16,7 +16,8 @@
|
||||
*/
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_syscalls.h>
|
||||
#include <core_linux_syscalls.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <linux_dataspace/linux_dataspace.h>
|
||||
|
@ -1,6 +1,6 @@
|
||||
TARGET = core
|
||||
REQUIRES = linux
|
||||
LIBS = cxx ipc heap core_printf child lock raw_server syscall rpath
|
||||
LIBS = cxx ipc heap core_printf child lock raw_server syscall
|
||||
|
||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||
|
||||
@ -25,7 +25,8 @@ SRC_CC = main.cc \
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/core/include \
|
||||
$(GEN_CORE_DIR)/include \
|
||||
$(REP_DIR)/src/platform
|
||||
$(REP_DIR)/src/platform \
|
||||
$(REP_DIR)/src/base/ipc
|
||||
|
||||
HOST_INC_DIR += /usr/include
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* \brief Linux resource path
|
||||
* \author Christian Helmuth
|
||||
* \date 2011-09-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/snprintf.h>
|
||||
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_rpath.h>
|
||||
|
||||
|
||||
namespace {
|
||||
struct Rpath
|
||||
{
|
||||
char string[32];
|
||||
|
||||
Rpath()
|
||||
{
|
||||
Genode::snprintf(string, sizeof(string), "/tmp/genode-%d", lx_getuid());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
char const * lx_rpath()
|
||||
{
|
||||
static Rpath rpath;
|
||||
|
||||
return rpath.string;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* \brief Linux resource path
|
||||
* \author Christian Helmuth
|
||||
* \date 2011-09-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _PLATFORM__LINUX_RPATH_H_
|
||||
#define _PLATFORM__LINUX_RPATH_H_
|
||||
|
||||
|
||||
/**
|
||||
* Return resource path for Genode
|
||||
*
|
||||
* Genode creates files for dataspaces and endpoints under in this directory.
|
||||
*/
|
||||
char const * lx_rpath();
|
||||
|
||||
#endif /* _PLATFORM__LINUX_RPATH_H_ */
|
@ -1,514 +0,0 @@
|
||||
/*
|
||||
* \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
|
||||
* 'ep-<thread id>-<role>'.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 _PLATFORM__LINUX_SOCKET_H_
|
||||
#define _PLATFORM__LINUX_SOCKET_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/ipc_generic.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/blocking.h>
|
||||
#include <base/snprintf.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Genode bindings to Linux kernel */
|
||||
#include <linux_rpath.h>
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
|
||||
extern "C" void wait_for_continue(void);
|
||||
extern "C" int raw_write_str(const char *str);
|
||||
|
||||
#define PRAW(fmt, ...) \
|
||||
do { \
|
||||
char str[128]; \
|
||||
Genode::snprintf(str, sizeof(str), \
|
||||
ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \
|
||||
raw_write_str(str); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/******************************
|
||||
** 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.
|
||||
*/
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
template <unsigned MAX_FDS>
|
||||
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 <unsigned MAX_FDS>
|
||||
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: Create socket address for server entrypoint at thread ID
|
||||
*/
|
||||
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_getpeername(sd, (sockaddr *)&name, &name_len);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* The socket name has the form '<rpath>/ep-<tid>'. Hence, to determine the
|
||||
* tid, we have to skip 'strlen(rpath)' and 'strlen("/ep-"). We use static
|
||||
* variables to determine length of 'rpath' only once because it is not
|
||||
* going to change at runtime.
|
||||
*/
|
||||
static size_t const rpath_len = Genode::strlen(lx_rpath());
|
||||
static size_t const ep_suffix = Genode::strlen("/ep-");
|
||||
|
||||
/*
|
||||
* Reply capabilities do not have a name because they are created via
|
||||
* 'socketpair'. Check if this function is called with such a socket
|
||||
* descriptor as argument.
|
||||
*/
|
||||
if (rpath_len + ep_suffix >= name_len) {
|
||||
PRAW("Error: unexpectedly short socket name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned tid = 0;
|
||||
if (Genode::ascii_to(name.sun_path + rpath_len + ep_suffix, &tid) == 0) {
|
||||
PRAW("Error: could not parse tid number");
|
||||
return -1;
|
||||
}
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Message object encapsulating data for sendmsg/recvmsg
|
||||
*/
|
||||
struct Message
|
||||
{
|
||||
public:
|
||||
|
||||
enum { MAX_SDS_PER_MSG = Genode::Msgbuf_base::MAX_CAPS_PER_MSG };
|
||||
|
||||
private:
|
||||
|
||||
msghdr _msg;
|
||||
sockaddr_un _addr;
|
||||
iovec _iovec;
|
||||
char _cmsg_buf[CMSG_SPACE(MAX_SDS_PER_MSG*sizeof(int))];
|
||||
|
||||
unsigned _num_sds;
|
||||
|
||||
public:
|
||||
|
||||
Message(void *buffer, size_t buffer_len) : _num_sds(0)
|
||||
{
|
||||
memset(&_msg, 0, sizeof(_msg));
|
||||
|
||||
/* initialize control message */
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
_msg.msg_control = _cmsg_buf;
|
||||
_msg.msg_controllen = sizeof(_cmsg_buf); /* buffer space available */
|
||||
_msg.msg_flags |= MSG_CMSG_CLOEXEC;
|
||||
cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(0);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
|
||||
/* initialize iovec */
|
||||
_msg.msg_iov = &_iovec;
|
||||
_msg.msg_iovlen = 1;
|
||||
|
||||
_iovec.iov_base = buffer;
|
||||
_iovec.iov_len = buffer_len;
|
||||
}
|
||||
|
||||
msghdr * msg() { return &_msg; }
|
||||
|
||||
void marshal_socket(int sd)
|
||||
{
|
||||
*((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd;
|
||||
|
||||
_num_sds++;
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(_num_sds*sizeof(int));
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
}
|
||||
|
||||
void accept_sockets(int num_sds)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(num_sds*sizeof(int));
|
||||
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
|
||||
}
|
||||
|
||||
int socket_at_index(int index) const
|
||||
{
|
||||
return *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index);
|
||||
}
|
||||
|
||||
unsigned num_sockets() const
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
|
||||
|
||||
if (!cmsg)
|
||||
return 0;
|
||||
|
||||
return (cmsg->cmsg_len - CMSG_ALIGN(sizeof(cmsghdr)))/sizeof(int);
|
||||
}
|
||||
};
|
||||
|
||||
} /* unnamed namespace */
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Extract socket desriptors from SCM message into 'Genode::Msgbuf'
|
||||
*/
|
||||
static void extract_sds_from_message(unsigned start_index, Message const &msg,
|
||||
Genode::Msgbuf_base &buf)
|
||||
{
|
||||
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 inline Genode::Native_connection_state lx_server_socket_pair(long thread_id)
|
||||
{
|
||||
Genode::Native_connection_state ncs;
|
||||
|
||||
/*
|
||||
* Main thread uses 'Ipc_server' for 'sleep_forever()' only. No need for
|
||||
* binding.
|
||||
*/
|
||||
if (thread_id == -1)
|
||||
return ncs;
|
||||
|
||||
Uds_addr addr(thread_id);
|
||||
|
||||
/*
|
||||
* 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(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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Wipe Unix domain socket from the file system. It will live as long as
|
||||
* there exist references to it in the form of file descriptors.
|
||||
*/
|
||||
lx_unlink(addr.sun_path);
|
||||
|
||||
return ncs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Send request to server and wait for reply
|
||||
*/
|
||||
static inline 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(send_msgbuf.buf, send_msg_len);
|
||||
|
||||
/* create reply channel */
|
||||
enum { LOCAL_SOCKET = 0, REMOTE_SOCKET = 1 };
|
||||
int reply_channel[2];
|
||||
|
||||
ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, reply_channel);
|
||||
if (ret < 0) {
|
||||
PRAW("lx_socketpair failed with %d", ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
/* assemble message */
|
||||
|
||||
/* marshal reply capability */
|
||||
send_msg.marshal_socket(reply_channel[REMOTE_SOCKET]);
|
||||
|
||||
/* marshal capabilities contained in 'send_msgbuf' */
|
||||
for (unsigned i = 0; i < send_msgbuf.used_caps(); i++)
|
||||
send_msg.marshal_socket(send_msgbuf.cap(i));
|
||||
|
||||
ret = lx_sendmsg(dst_sd, send_msg.msg(), 0);
|
||||
if (ret < 0) {
|
||||
PRAW("[%d] lx_sendmsg to sd %d failed with %d in lx_call()",
|
||||
lx_getpid(), dst_sd, ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
/* receive reply */
|
||||
|
||||
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("[%d] lx_recvmsg failed with %d in lx_call()", lx_getpid(), ret);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
extract_sds_from_message(0, recv_msg, recv_msgbuf);
|
||||
|
||||
/* destroy reply channel */
|
||||
lx_close(reply_channel[LOCAL_SOCKET]);
|
||||
lx_close(reply_channel[REMOTE_SOCKET]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Wait for request from client
|
||||
*
|
||||
* \return socket descriptor of reply capability
|
||||
*/
|
||||
static inline int lx_wait(Genode::Native_connection_state &cs,
|
||||
Genode::Msgbuf_base &recv_msgbuf)
|
||||
{
|
||||
Message msg(recv_msgbuf.buf, recv_msgbuf.size());
|
||||
|
||||
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
|
||||
|
||||
int ret = lx_recvmsg(cs.server_sd, msg.msg(), 0);
|
||||
if (ret < 0) {
|
||||
PRAW("lx_recvmsg failed with %d in lx_wait(), sd=%d", ret, cs.server_sd);
|
||||
throw Genode::Ipc_error();
|
||||
}
|
||||
|
||||
int const reply_socket = msg.socket_at_index(0);
|
||||
|
||||
extract_sds_from_message(1, msg, recv_msgbuf);
|
||||
|
||||
return reply_socket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility: Send reply to client
|
||||
*/
|
||||
static inline void lx_reply(int reply_socket,
|
||||
Genode::Msgbuf_base &send_msgbuf,
|
||||
size_t msg_len)
|
||||
{
|
||||
Message msg(send_msgbuf.buf, msg_len);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
PRAW("lx_sendmsg failed with %d in lx_reply()", ret);
|
||||
|
||||
lx_close(reply_socket);
|
||||
}
|
||||
|
||||
#endif /* _PLATFORM__LINUX_SOCKET_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Linux system-call wrappers
|
||||
* \brief Linux system-call bindings
|
||||
* \author Norman Feske
|
||||
* \date 2008-10-22
|
||||
*
|
||||
@ -7,8 +7,8 @@
|
||||
* interface.
|
||||
*
|
||||
* From within the framework libraries, we have to use the Linux syscall
|
||||
* interface directly rather than relying on convenient libC functions to be
|
||||
* able to link this part of the framework to a custom libC. Otherwise, we
|
||||
* interface directly rather than relying on convenient libc functions to be
|
||||
* able to link this part of the framework to a custom libc. Otherwise, we
|
||||
* would end up with very nasty cyclic dependencies when using framework
|
||||
* functions such as IPC from the libC back end.
|
||||
*
|
||||
@ -36,14 +36,33 @@
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
|
||||
/***********************************
|
||||
** Low-level debugging utilities **
|
||||
***********************************/
|
||||
|
||||
extern "C" void wait_for_continue(void);
|
||||
extern "C" int raw_write_str(const char *str);
|
||||
|
||||
#define PRAW(fmt, ...) \
|
||||
do { \
|
||||
char str[128]; \
|
||||
Genode::snprintf(str, sizeof(str), \
|
||||
ESC_ERR fmt ESC_END "\n", ##__VA_ARGS__); \
|
||||
raw_write_str(str); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*********************************************************
|
||||
** System-call bindings implemented in syscall library **
|
||||
*********************************************************/
|
||||
|
||||
extern "C" long lx_syscall(int number, ...);
|
||||
extern "C" int lx_clone(int (*fn)(void *), void *child_stack,
|
||||
int flags, void *arg);
|
||||
@ -65,24 +84,12 @@ inline int lx_close(int fd)
|
||||
}
|
||||
|
||||
|
||||
inline int lx_dup(int fd)
|
||||
{
|
||||
return lx_syscall(SYS_dup, 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);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
** Functions used by the IPC framework **
|
||||
*****************************************/
|
||||
@ -97,14 +104,6 @@ inline int lx_socketcall(int call, unsigned long *args)
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline int lx_socket(int domain, int type, int protocol)
|
||||
{
|
||||
unsigned long args[3] = { domain, type, protocol };
|
||||
return lx_socketcall(SYS_SOCKET, args);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
|
||||
{
|
||||
unsigned long args[4] = { domain, type, protocol, (unsigned long)sd };
|
||||
@ -112,22 +111,6 @@ inline int lx_socketpair(int domain, int type, int protocol, int sd[2])
|
||||
}
|
||||
|
||||
|
||||
inline int lx_bind(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
unsigned long args[3] = { sockfd, (unsigned long)addr, addrlen };
|
||||
return lx_socketcall(SYS_BIND, args);
|
||||
}
|
||||
|
||||
|
||||
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 };
|
||||
@ -150,25 +133,6 @@ inline int lx_getpeername(int sockfd, struct sockaddr *name, socklen_t *namelen)
|
||||
|
||||
#else
|
||||
|
||||
inline int lx_socket(int domain, int type, int protocol)
|
||||
{
|
||||
return lx_syscall(SYS_socket, domain, type, protocol);
|
||||
}
|
||||
|
||||
inline int lx_bind(int sockfd, const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
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);
|
||||
@ -209,12 +173,6 @@ inline void lx_exit_group(int status)
|
||||
/* O_CLOEXEC is a GNU extension so we provide it here */
|
||||
enum { LX_O_CLOEXEC = 02000000 };
|
||||
|
||||
inline int lx_open(const char *pathname, int flags, mode_t mode = 0)
|
||||
{
|
||||
return lx_syscall(SYS_open, pathname, flags, mode);
|
||||
}
|
||||
|
||||
|
||||
inline void *lx_mmap(void *start, Genode::size_t length, int prot, int flags,
|
||||
int fd, off_t offset)
|
||||
{
|
||||
@ -262,36 +220,6 @@ inline Genode::addr_t lx_vm_reserve(Genode::addr_t base, Genode::size_t size)
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** Functions used by core's ram-session support code **
|
||||
*******************************************************/
|
||||
|
||||
inline int lx_mkdir(char const *pathname, mode_t mode)
|
||||
{
|
||||
return lx_syscall(SYS_mkdir, pathname, mode);
|
||||
}
|
||||
|
||||
|
||||
inline int lx_ftruncate(int fd, unsigned long length)
|
||||
{
|
||||
return lx_syscall(SYS_ftruncate, fd, length);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************
|
||||
** Functions used by core's rom-session support code **
|
||||
*******************************************************/
|
||||
|
||||
inline int lx_stat(const char *path, struct stat64 *buf)
|
||||
{
|
||||
#ifdef _LP64
|
||||
return lx_syscall(SYS_stat, path, buf);
|
||||
#else
|
||||
return lx_syscall(SYS_stat64, path, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
** Functions used by thread lib and core's cancel-blocking mechanism **
|
||||
***********************************************************************/
|
||||
@ -354,17 +282,6 @@ inline int lx_sigaction(int signum, void (*handler)(int))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send signal to process
|
||||
*
|
||||
* This function is used by core to kill processes.
|
||||
*/
|
||||
inline int lx_kill(int pid, int signal)
|
||||
{
|
||||
return lx_syscall(SYS_kill, pid, signal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send signal to thread
|
||||
*
|
||||
@ -483,4 +400,5 @@ inline bool lx_sigsetmask(int signum, bool state)
|
||||
return old_sigmask.is_set(signum);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _PLATFORM__LINUX_SYSCALLS_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user