Imported Genode release 11.11

This commit is contained in:
Genode Labs
2011-12-22 16:19:25 +01:00
committed by Christian Helmuth
parent 6bcc9aef0e
commit da4e1feaa5
2462 changed files with 320115 additions and 3 deletions

View File

@ -0,0 +1,26 @@
This directory contains a HTTP client that implements Genode's block session
interface as a front-end. This way you can incorporate arbitrary files via.
HTTP requests and export them as a block device within Genode.
Usage
-----
Config file snippet:
!<start name="http_blkdrv">
! <resource name="RAM" quantum="1M" />
! <provides><service name="Block"/></provides> <!-- Mandatory -->
! <config>
!
! <!-- File to export as a block device.
! Syntax:'http:://<host>[:port]/<path to file>' -->
! <uri>http://kc86.genode.labs:80/file.iso</uri>
!
! <!- The block size of the exported block device. This is optional, the
! default is 512 bytes. -->
! <block-size>2048</block-size>
!
! </config>
!</start>

View File

@ -0,0 +1,305 @@
/*
* \brief HTTP protocol parts
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \date 2010-08-19
*/
/*
* Copyright (C) 2010-2011 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.
*/
#include <base/child.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <lwip/genode.h>
extern "C" {
#include <lwip/netdb.h>
}
#include "http.h"
using namespace Genode;
/*
* Debugging output
*/
static const int verbose = 0;
enum {
/* HTTP status codes */
HTTP_SUCC_OK = 200,
HTTP_SUCC_PARTIAL = 206,
/* Size of our local buffer */
HTTP_BUF = 2048,
};
/* Tokenizer policy */
struct Scanner_policy_file
{
static bool identifier_char(char c, unsigned /* i */)
{
return c != ':' && c != 0 && c != ' ' && c != '\n';
}
};
typedef ::Genode::Token<Scanner_policy_file> Http_token;
void Http::cmd_head()
{
const char *http_templ = "%s %s HTTP/1.1\r\n"
"Host: %s\r\n"
"\r\n";
int length = snprintf(_http_buf, HTTP_BUF, http_templ, "HEAD", _path, _host);
if (lwip_write(_fd, _http_buf, length) != length) {
PERR("Write error");
throw Http::Socket_error();
}
}
void Http::connect()
{
_fd = lwip_socket(AF_INET, SOCK_STREAM, 0);
if (_fd < 0) {
PERR("No socket avaiable");
throw Http::Socket_error();
}
if (lwip_connect(_fd, _info->ai_addr, sizeof(*(_info->ai_addr))) < 0) {
PERR("Connect failed");
throw Http::Socket_error();
}
}
void Http::reconnect(){ lwip_close(_fd); connect(); }
void Http::resolve_uri()
{
struct addrinfo *info;
if (lwip_getaddrinfo(_host, _port, 0, &info)) {
PERR("Error: Host %s not found", _host);
throw Http::Uri_error();
}
env()->heap()->alloc(sizeof(struct addrinfo), &_info);
Genode::memcpy(_info, info, sizeof(struct addrinfo));
}
Genode::size_t Http::read_header()
{
bool header = true; size_t i = 0;
while (header) {
if (!lwip_read(_fd, &_http_buf[i], 1))
throw Http::Socket_closed();
/* DEBUG: Genode::printf("%c", _http_buf[i]); */
if (i >= 3 && _http_buf[i - 3] == '\r' && _http_buf[i - 2] == '\n'
&& _http_buf[i - 1] == '\r' && _http_buf[i - 0] == '\n')
header = false;
if (++i >= HTTP_BUF) {
PERR("Buffer overflow");
throw Http::Socket_error();
}
}
/* scan for status code */
Http_token t(_http_buf, i);
for (int count = 0;; t = t.next()) {
if (t.type() != Http_token::IDENT)
continue;
if (count) {
ascii_to(t.start(), &_http_ret);
break;
}
count++;
}
return i;
}
void Http::get_capacity()
{
cmd_head();
size_t len = read_header();
char buf[32];
Http_token t(_http_buf, len);
bool key = false;
while (t) {
if (t.type() != Http_token::IDENT) {
t = t.next();
continue;
}
if (key) {
ascii_to(t.start(), &_size);
if (verbose)
PDBG("File size: %zu bytes", _size);
break;
}
t.string(buf, 32);
if (!Genode::strcmp(buf, "Content-Length", 32))
key = true;
t = t.next();
}
}
void Http::do_read(void * buf, size_t size)
{
size_t buf_fill = 0;
while (buf_fill < size) {
int part;
if ((part = lwip_read(_fd, (void *)((addr_t)buf + buf_fill),
size - buf_fill)) <= 0) {
PERR("Error: Reading data (%d)", errno);
throw Http::Socket_error();
}
buf_fill += part;
}
if (verbose)
PDBG("Read %zu/%zu", buf_fill, size);
}
Http::Http(char *uri, size_t length) : _port((char *)"80")
{
env()->heap()->alloc(HTTP_BUF, &_http_buf);
/* parse URI */
parse_uri(uri, length);
/* search for host */
resolve_uri();
/* connect to host */
connect();
/* retrieve file info */
get_capacity();
}
Http::~Http()
{
env()->heap()->free(_host, Genode::strlen(_host) + 1);
env()->heap()->free(_path, Genode::strlen(_path) + 2);
env()->heap()->free(_http_buf, HTTP_BUF);
env()->heap()->free(_info, sizeof(struct addrinfo));
}
void Http::parse_uri(char *uri, size_t length)
{
/* strip possible http prefix */
const char *http = "http://";
size_t http_len = Genode::strlen(http);
if (!strcmp(http, uri, http_len)) {
uri += http_len;
length -= http_len;
}
/* set host and file path */
size_t i;
for (i = 0; i < length && uri[i] != '/'; i++) ;
env()->heap()->alloc(i + 1, &_host);
Genode::strncpy(_host, uri, i + 1);
env()->heap()->alloc(length - i + 1, &_path);
Genode::strncpy(_path, uri + i, length - i + 1);
/* look for port */
size_t len = Genode::strlen(_host);
for (i = 0; i < len && _host[i] != ':'; i++) ;
if (i < len) {
_port = &_host[i + 1];
_host[i] = '\0';
}
if (verbose)
PDBG("Port: %s", _port);
}
void Http::cmd_get(size_t file_offset, size_t size, off_t offset)
{
if (verbose)
PDBG("Read: offs %zu size: %zu I/O offs: %lx", file_offset, size, offset);
while (true) {
const char *http_templ = "GET %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Range: bytes=%lu-%lu\r\n"
"\r\n";
int length = snprintf(_http_buf, HTTP_BUF, http_templ, _path, _host,
file_offset, file_offset + size - 1);
if (lwip_write(_fd, _http_buf, length) < 0) {
if (errno == ESHUTDOWN)
reconnect();
if (lwip_write(_fd, _http_buf, length) < 0)
throw Http::Socket_error();
}
try {
read_header();
} catch (Http::Socket_closed) {
reconnect();
continue;
}
if (_http_ret != HTTP_SUCC_PARTIAL) {
PERR("Error: Server returned %u", _http_ret);
throw Http::Server_error();
}
do_read((void *)(_base_addr + offset), size);
return;
}
}
void __attribute__((constructor)) init()
{
lwip_tcpip_init();
if (lwip_nic_init(0, 0, 0)) {
PERR("DHCP failed");
throw -1;
}
}

View File

@ -0,0 +1,122 @@
/*
* \brief HTTP back-end interface
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
* \date 2010-08-24
*/
/*
* Copyright (C) 2010-2011 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 _HTTP_H_
#define _HTTP_H_
#include <base/stdint.h>
struct addrinfo;
class Http
{
typedef Genode::size_t size_t;
typedef Genode::addr_t addr_t;
typedef Genode::off_t off_t;
private:
size_t _size; /* number of bytes in file */
char *_host; /* host name */
char *_port; /* host port */
char *_path; /* absolute file path on host */
char *_http_buf; /* internal data buffer */
unsigned _http_ret; /* HTTP status code */
struct addrinfo *_info; /* Resolved address info for host */
int _fd; /* Socket file handle */
addr_t _base_addr; /* Address of I/O dataspace */
/*
* Send 'HEAD' command
*/
void cmd_head();
/*
* Connect to host
*/
void connect();
/*
* Re-connect to host
*/
void reconnect();
/*
* Set URI of remote file
*/
void parse_uri(char *uri, size_t length);
/*
* Resolve host
*/
void resolve_uri();
/*
* Read HTTP header and parse server-status code
*/
size_t read_header();
/*
* Determine remote-file size
*/
void get_capacity();
/*
* Read 'size' bytes into buffer
*/
void do_read(void * buf, size_t size);
public:
/*
* Constructor (default block size is 512 Bytes, default host port is 80
*/
Http(char *uri, size_t length);
/*
* Destructor
*/
~Http();
/**
* Read remote file size
*
* \return Remote file size in bytes
*/
size_t file_size() { return _size; }
/**
* Set base address of I/O dataspace
*
* \param base_addr Base of dataspace
*/
void base_addr(addr_t base_addr) { _base_addr = base_addr; }
/**
* Send 'GET' command
*
* \param file_offset Read from offset of remote file
* \param size Number of byts to transfer
* \param offset Offset in I/O dataspace
*/
void cmd_get(size_t file_offset, size_t size, off_t offset);
/* Exceptions */
class Exception : public ::Genode::Exception { };
class Uri_error : public Exception { };
class Socket_error : public Exception { };
class Socket_closed : public Exception { };
class Server_error : public Exception { };
};
#endif /* _HTTP_H_ */

View File

@ -0,0 +1,289 @@
/*
* \brief Block interface for HTTP block driver
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2010-08-24
*/
/*
* Copyright (C) 2010-2011 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/thread.h>
#include <base/sleep.h>
#include <base/semaphore.h>
#include <block_session/rpc_object.h>
#include <cap_session/connection.h>
#include <root/component.h>
#include <os/config.h>
/* local includes */
#include "http.h"
using namespace Genode;
namespace Block {
class Http_interface
{
private:
size_t _block_size;
Http *_http;
public:
Http_interface() : _block_size(512), _http(0) {}
static Http_interface* obj()
{
static Http_interface _obj;
return &_obj;
}
void block_size(size_t block_size)
{
_block_size = block_size;
}
size_t block_size() { return _block_size; }
void base_addr(addr_t base_addr)
{
_http->base_addr(base_addr);
}
void read(size_t block_nr, size_t block_count, off_t offset)
{
_http->cmd_get(block_nr * _block_size, block_count * _block_size, offset);
}
size_t block_count()
{
return _http->file_size() / _block_size;
}
void uri(char *uri, size_t length)
{
_http = new(env()->heap()) Http(uri, length);
}
Http * http_blk() { return _http; }
};
class Session_component : public Session_rpc_object
{
private:
class Tx_thread : public Genode::Thread<8192>
{
private:
Session_component *_session;
public:
Tx_thread(Session_component *session)
: Genode::Thread<8192>("worker"), _session(session) { }
void entry()
{
using namespace Genode;
Session_component::Tx::Sink *tx_sink = _session->tx_sink();
Block::Packet_descriptor packet;
_session->tx_ready();
/* handle requests */
while (true) {
/* blocking-get packet from client */
packet = tx_sink->get_packet();
if (!packet.valid()) {
PWRN("received invalid packet");
continue;
}
packet.succeeded(false);
switch (packet.operation()) {
case Block::Packet_descriptor::READ:
try {
Http_interface::obj()->read(packet.block_number(),
packet.block_count(),
packet.offset());
packet.succeeded(true);
}
catch (Http::Socket_error) { PERR("socket error"); }
catch (Http::Server_error) { PERR("server error"); }
break;
case Block::Packet_descriptor::WRITE:
break;
default:
PWRN("received invalid packet");
continue;
}
/* acknowledge packet to the client */
if (!tx_sink->ready_to_ack())
PDBG("need to wait until ready-for-ack");
tx_sink->acknowledge_packet(packet);
}
}
};
private:
Genode::Dataspace_capability _tx_ds; /* buffer for tx channel */
Genode::Semaphore _startup_sema; /* thread startup sync */
Tx_thread _tx_thread;
public:
/**
* Constructor
*
* \param tx_ds dataspace used for tx channel
*/
Session_component(Genode::Dataspace_capability tx_ds,
Genode::Rpc_entrypoint &ep)
: Session_rpc_object(tx_ds, ep), _tx_ds(tx_ds),
_startup_sema(0), _tx_thread(this)
{
/*
* Map packet stream
*/
addr_t base = env()->rm_session()->attach(tx_ds);
Http_interface::obj()->base_addr(base);
_tx_thread.start();
_startup_sema.down();
}
void info(Genode::size_t *blk_count, Genode::size_t *blk_size,
Operations *ops)
{
*blk_count = Http_interface::obj()->block_count();
*blk_size = Http_interface::obj()->block_size();
ops->set_operation(Packet_descriptor::READ);
}
/**
* Signal indicating that transmit thread is ready
*/
void tx_ready() { _startup_sema.up(); }
};
/*
* Allow one client only
*/
/*
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Session_component> Root_component;
/**
* Root component, handling new session requests
*/
class Root : public Root_component
{
protected:
/**
* Always returns the singleton block-session component
*/
Session_component *_create_session(const char *args)
{
using namespace Genode;
Genode::size_t ram_quota =
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
Genode::size_t tx_buf_size =
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
/* delete ram quota by the memory needed for the session */
Genode::size_t session_size = max((Genode::size_t)4096,
sizeof(Session_component)
+ sizeof(Allocator_avl));
if (ram_quota < session_size)
throw Root::Quota_exceeded();
/*
* Check if donated ram quota suffices for both
* communication buffers. Also check both sizes separately
* to handle a possible overflow of the sum of both sizes.
*/
if (tx_buf_size > ram_quota - session_size) {
PERR("insufficient 'ram_quota', got %zd, need %zd",
ram_quota, tx_buf_size + session_size);
throw Root::Quota_exceeded();
}
return new (md_alloc())
Session_component(env()->ram_session()->alloc(tx_buf_size), *ep());
}
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc)
: Root_component(session_ep, md_alloc) { }
};
}
static void process_config()
{
using namespace Genode;
Xml_node config_node = config()->xml_node();
bool uri = false;
for (unsigned i = 0; i < config_node.num_sub_nodes(); ++i) {
Xml_node file_node = config_node.sub_node(i);
if (file_node.has_type("uri")) {
Block::Http_interface::obj()->uri(file_node.content_addr(), file_node.content_size());
uri = true;
}
if (file_node.has_type("block-size")) {
size_t blk_size;
file_node.value(&blk_size);
Block::Http_interface::obj()->block_size(blk_size);
}
}
if (!uri)
throw Http::Uri_error();
}
int main()
{
enum { STACK_SIZE = 4*1024 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "http_block_ep");
process_config();
static Block::Root block_root(&ep, env()->heap());
env()->parent()->announce(ep.manage(&block_root));
sleep_forever();
return 0;
}

View File

@ -0,0 +1,5 @@
TARGET = http_block
SRC_CC = main.cc http.cc
LIBS = signal server cxx env lwip libc

View File

@ -0,0 +1,12 @@
TCP terminal is a service that provides Genode's terminal-session interface
via individual TCP connections. It supports multiple clients. The TCP port
to be used for each client is defined in as session policy in the config node
of the TCP server:
! <config>
! <policy label="client" port="8181"/>
! <policy label="another_client" port="8282"/>
! </config>
For an example of how to use the TCP terminal, please refer to the run script
at 'gems/run/tcp_terminal.run'.

View File

@ -0,0 +1,514 @@
/*
* \brief Service providing the 'Terminal_session' interface via TCP
* \author Norman Feske
* \date 2011-09-07
*/
/*
* Copyright (C) 2011 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 <util/list.h>
#include <util/misc_math.h>
#include <base/printf.h>
#include <base/rpc_server.h>
#include <base/heap.h>
#include <root/component.h>
#include <terminal_session/terminal_session.h>
#include <cap_session/connection.h>
#include <os/attached_ram_dataspace.h>
#include <os/session_policy.h>
/* socket API */
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
static bool const verbose = true;
class Open_socket : public Genode::List<Open_socket>::Element
{
private:
/**
* Socket descriptor for listening to a new TCP connection
*/
int _listen_sd;
/**
* Socket descriptor for open TCP connection
*/
int _sd;
/**
* Signal handler to be informed about the established connection
*/
Genode::Signal_context_capability _connected_sigh;
/**
* Signal handler to be informed about data available to read
*/
Genode::Signal_context_capability _read_avail_sigh;
/**
* Buffer for incoming data
*
* This buffer is used for synchronizing the reception of data in the
* main thread ('watch_sockets_for_incoming_data') and the entrypoint
* thread ('read'). The main thread fills the buffer if its not already
* occupied and the entrypoint thread consumes the buffer. When the
* buffer becomes occupied, the corresponding socket gets removed from
* the 'rfds' set of 'select()' until a read request from the terminal
* client comes in.
*/
enum { READ_BUF_SIZE = 4096 };
char _read_buf[READ_BUF_SIZE];
Genode::size_t _read_buf_bytes_used;
/**
* Establish remote connection
*
* \return socket descriptor used for the remote TCP connection
*/
static int _remote_listen(int tcp_port)
{
int listen_sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_sd == -1) {
PERR("socket creation failed");
return -1;
}
sockaddr_in sockaddr;
sockaddr.sin_family = PF_INET;
sockaddr.sin_port = htons (tcp_port);
sockaddr.sin_addr.s_addr = INADDR_ANY;
if (bind(listen_sd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
PERR("bind to port %d failed", tcp_port);
return -1;
}
if (listen(listen_sd, 1)) {
PERR("listen failed");
return -1;
}
Genode::printf("listening on port %d...\n", tcp_port);
return listen_sd;
}
public:
Open_socket(int tcp_port);
~Open_socket();
/**
* Return socket descriptor for listening to new connections
*/
int listen_sd() const { return _listen_sd; }
/**
* Return true if all steps of '_remote_listen' succeeded
*/
bool listen_sd_valid() const { return _listen_sd != -1; }
/**
* Return socket descriptor of the connection
*/
int sd() const { return _sd; }
/**
* Register signal handler to be notified once we accepted the TCP
* connection
*/
void connected_sigh(Genode::Signal_context_capability sigh) { _connected_sigh = sigh; }
/**
* Register signal handler to be notified when data is available for
* reading
*/
void read_avail_sigh(Genode::Signal_context_capability sigh)
{
_read_avail_sigh = sigh;
/* if read data is available right now, deliver signal immediately */
if (!read_buffer_empty() && _read_avail_sigh.valid())
Genode::Signal_transmitter(_read_avail_sigh).submit();
}
/**
* Accept new connection, defining the connection's socket descriptor
*
* This function is called by the 'select()' thread when a new
* connection is pending.
*/
void accept_remote_connection()
{
struct sockaddr addr;
socklen_t len = sizeof(addr);
_sd = accept(_listen_sd, &addr, &len);
if (_sd > 0)
Genode::printf("connection established\n");
/*
* Inform client about the finished initialization of the terminal
* session
*/
if (_connected_sigh.valid())
Genode::Signal_transmitter(_connected_sigh).submit();
}
/**
* Return true if TCP connection is established
*
* If the return value is false, we are still in listening more
* and have not yet called 'accept()'.
*/
bool connection_established() const { return _sd != -1; }
/**
* Fetch data from socket into internal read buffer
*/
void fill_read_buffer_and_notify_client()
{
if (_read_buf_bytes_used) {
PWRN("read buffer already in use");
return;
}
/* read from socket */
_read_buf_bytes_used = ::read(_sd, _read_buf, sizeof(_read_buf));
/* notify client about bytes available for reading */
if (_read_avail_sigh.valid())
Genode::Signal_transmitter(_read_avail_sigh).submit();
}
/**
* Flush internal read buffer into destination buffer
*/
Genode::size_t flush_read_buffer(char *dst, Genode::size_t dst_len)
{
Genode::size_t num_bytes = Genode::min(dst_len, _read_buf_bytes_used);
Genode::memcpy(dst, _read_buf, num_bytes);
_read_buf_bytes_used = 0;
return num_bytes;
}
/**
* Return true if the internal read buffer is ready to receive data
*/
bool read_buffer_empty() const { return _read_buf_bytes_used == 0; }
};
class Open_socket_pool
{
private:
/**
* Protection for '_list'
*/
Genode::Lock _lock;
/**
* List of open sockets
*/
Genode::List<Open_socket> _list;
/**
* Number of currently open sockets
*/
int _count;
/**
* Pipe used to synchronize 'select()' loop with the entrypoint thread
*/
int sync_pipe_fds[2];
/**
* Intercept the blocking state of the current 'select()' call
*/
void _wakeup_select()
{
char c = 0;
::write(sync_pipe_fds[1], &c, sizeof(c));
}
public:
Open_socket_pool() : _count(0)
{
pipe(sync_pipe_fds);
}
void insert(Open_socket *s)
{
Genode::Lock::Guard guard(_lock);
_list.insert(s);
_count++;
_wakeup_select();
}
void remove(Open_socket *s)
{
Genode::Lock::Guard guard(_lock);
_list.remove(s);
_count--;
_wakeup_select();
}
void update_sockets_to_watch()
{
_wakeup_select();
}
void watch_sockets_for_incoming_data()
{
/* prepare arguments for 'select()' */
fd_set rfds;
int nfds = 0;
{
Genode::Lock::Guard guard(_lock);
/* collect file descriptors of all open sessions */
FD_ZERO(&rfds);
for (Open_socket *s = _list.first(); s; s = s->next()) {
/*
* If one of the steps of creating the listen socket
* failed, skip the session.
*/
if (!s->listen_sd_valid())
continue;
/*
* If the connection is not already established, tell
* 'select' to notify us about a new connection.
*/
if (!s->connection_established()) {
nfds = Genode::max(nfds, s->listen_sd());
FD_SET(s->listen_sd(), &rfds);
continue;
}
/*
* The connection is established. We watch the connection's
* file descriptor for reading, but only if our buffer can
* take new data. Otherwise, we let the incoming data queue
* up in the TCP/IP stack.
*/
nfds = Genode::max(nfds, s->sd());
if (s->read_buffer_empty())
FD_SET(s->sd(), &rfds);
}
/* add sync pipe to set of file descriptors to watch */
FD_SET(sync_pipe_fds[0], &rfds);
nfds = Genode::max(nfds, sync_pipe_fds[0]);
}
/* block for incoming data or sync-pipe events */
select(nfds + 1, &rfds, NULL, NULL, NULL);
/* check if we were woken up via the sync pipe */
if (FD_ISSET(sync_pipe_fds[0], &rfds)) {
char c = 0;
::read(sync_pipe_fds[0], &c, 1);
return;
}
/* read pending data from sockets */
{
Genode::Lock::Guard guard(_lock);
for (Open_socket *s = _list.first(); s; s = s->next()) {
/* look for new connection */
if (!s->connection_established()) {
if (FD_ISSET(s->listen_sd(), &rfds))
s->accept_remote_connection();
continue;
}
/* connection is established, look for incoming data */
if (FD_ISSET(s->sd(), &rfds))
s->fill_read_buffer_and_notify_client();
}
}
}
};
Open_socket_pool *open_socket_pool()
{
static Open_socket_pool inst;
return &inst;
}
Open_socket::Open_socket(int tcp_port)
: _listen_sd(_remote_listen(tcp_port)), _sd(-1)
{
open_socket_pool()->insert(this);
}
Open_socket::~Open_socket()
{
close(_sd);
open_socket_pool()->remove(this);
}
namespace Terminal {
class Session_component : public Genode::Rpc_object<Session, Session_component>,
public Open_socket
{
private:
Genode::Attached_ram_dataspace _io_buffer;
public:
Session_component(Genode::size_t io_buffer_size, int tcp_port)
:
Open_socket(tcp_port),
_io_buffer(Genode::env()->ram_session(), io_buffer_size)
{ }
/********************************
** Terminal session interface **
********************************/
Size size() { return Size(0, 0); }
bool avail()
{
return !read_buffer_empty();
}
Genode::size_t _read(Genode::size_t dst_len)
{
Genode::size_t num_bytes =
flush_read_buffer(_io_buffer.local_addr<char>(),
Genode::min(_io_buffer.size(), dst_len));
/*
* If read buffer was in use, look if more data is buffered in
* the TCP/IP stack.
*/
if (num_bytes)
open_socket_pool()->update_sockets_to_watch();
return num_bytes;
}
void _write(Genode::size_t num_bytes)
{
/* sanitize argument */
num_bytes = Genode::min(num_bytes, _io_buffer.size());
/* write data to socket, assuming that it won't block */
if (::write(sd(), _io_buffer.local_addr<char>(), num_bytes) < 0)
PERR("write error, dropping data");
}
Genode::Dataspace_capability _dataspace()
{
return _io_buffer.cap();
}
void read_avail_sigh(Genode::Signal_context_capability sigh)
{
Open_socket::read_avail_sigh(sigh);
}
void connected_sigh(Genode::Signal_context_capability sigh)
{
Open_socket::connected_sigh(sigh);
}
Genode::size_t read(void *buf, Genode::size_t) { return 0; }
Genode::size_t write(void const *buf, Genode::size_t) { return 0; }
};
class Root_component : public Genode::Root_component<Session_component>
{
protected:
Session_component *_create_session(const char *args)
{
/*
* XXX read I/O buffer size from args
*/
Genode::size_t io_buffer_size = 4096;
try {
Genode::Session_policy policy(args);
unsigned tcp_port = 0;
policy.attribute("port").value(&tcp_port);
return new (md_alloc())
Session_component(io_buffer_size, tcp_port);
} catch (Genode::Xml_node::Nonexistent_attribute) {
PERR("Missing \"port\" attribute in policy definition");
throw Genode::Root::Unavailable();
} catch (Genode::Session_policy::No_policy_defined) {
PERR("Invalid session request, no matching policy");
throw Genode::Root::Unavailable();
}
}
public:
/**
* Constructor
*/
Root_component(Genode::Rpc_entrypoint *ep,
Genode::Allocator *md_alloc)
:
Genode::Root_component<Session_component>(ep, md_alloc)
{ }
};
}
int main()
{
using namespace Genode;
Genode::printf("--- TCP terminal started ---\n");
/* initialize entry point that serves the root interface */
enum { STACK_SIZE = 4*4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "terminal_ep");
static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session());
/* create root interface for service */
static Terminal::Root_component root(&ep, &sliced_heap);
/* announce service at our parent */
env()->parent()->announce(ep.manage(&root));
for (;;)
open_socket_pool()->watch_sockets_for_incoming_data();
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = tcp_terminal
SRC_CC = main.cc
LIBS = env cxx server libc libc_lwip_nic_dhcp libc_log libc_lock_pipe

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,4 @@
TARGET = terminal
LIBS = cxx env server signal
SRC_CC = main.cc
SRC_BIN = mono.tff