remote_rom: improvements and refactoring
Avoid a runtime warning message since our backend does not provide such constructor functions yet. If a backend requires them, it should initiate their execution by itself within the backend init functions. In coherence with the size_guard idea, the remote_rom packets are are separated into a simple layer packet and a data packet. While basically only managing common control informations, the layer packet may carry any payload. The data packet, instead, manages the transmission of the actual ROM payload and can be attached to the layer packet. This simplifies the management of the notification packets UPDATE and SIGNAL since they do not contain fields like 'offset' or 'payload_size' anymore. Now, a single thread manages all incoming RPC calls, signals and (thus) network packets. This will hopefully make further synchronization enhancements a lot easier. Further changes: * Following data packets are identified as such by their offset instead of their packet type field. This simplifies the protocol. * reduced redundancy in the packet building code * rewrap lines with >79 columns * fix compiler warnings * split backend code * Remove a few unnecessary include and using directives. * In order to avoid global variables across modules, 'verbose' is a member variable now. Later, its value may be set via constructor. * The nested Rx class is merged with Backend_base. This way, we avoid unnecessary maintenance as long as we don't have a clear design for ROM multiplexing which may require the management of multiple IP addresses etc. * The HANDLER template argument is removed since client and server inherit from Backend_base anyway. The receive method is virtual now. * The signals packet_avail and ready_to_ack are directly passed to the same signal handler now. * Remove unnecessarily public/protected visibility from some members. * Remove and add unnecessary and, due to inclusion order, secretly missing include directives, respectively.
This commit is contained in:
committed by
Norman Feske
parent
5627797e77
commit
c137c595c8
@@ -1,554 +0,0 @@
|
||||
/*
|
||||
* \brief TODO
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-18
|
||||
*/
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/exception.h>
|
||||
#include <base/log.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
|
||||
#include <backend_base.h>
|
||||
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/connection.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/ipv4.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
bool verbose = false;
|
||||
using Genode::size_t;
|
||||
using Genode::uint16_t;
|
||||
using Genode::uint32_t;
|
||||
using Genode::Cstring;
|
||||
using Genode::Packet_descriptor;
|
||||
using Genode::env;
|
||||
using Net::Ethernet_frame;
|
||||
using Net::Ipv4_packet;
|
||||
using Net::Mac_address;
|
||||
using Net::Ipv4_address;
|
||||
|
||||
template <class>
|
||||
class Backend_base;
|
||||
class Backend_server;
|
||||
class Backend_client;
|
||||
|
||||
struct Packet_base;
|
||||
struct SignalPacket;
|
||||
struct UpdatePacket;
|
||||
struct DataPacket;
|
||||
};
|
||||
|
||||
/* Packet format we use for inter-system communication */
|
||||
/* FIXME do not inherit from Ethernet_frame and Ipv4_packet but use construct_at_data with size_guard */
|
||||
class Remote_rom::Packet_base : public Ethernet_frame, public Ipv4_packet
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
MAX_NAME_LEN = 64 /* maximum length of the module name */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SIGNAL = 1, /* signal that ROM content has changed */
|
||||
UPDATE = 2, /* request transmission of updated content */
|
||||
DATA = 3, /* first data packet */
|
||||
DATA_CONT = 4, /* following data packets */
|
||||
} Type;
|
||||
|
||||
protected:
|
||||
char _module_name[MAX_NAME_LEN]; /* the ROM module name */
|
||||
Type _type; /* packet type */
|
||||
uint32_t _content_size; /* ROM content size in bytes */
|
||||
uint32_t _offset; /* offset in bytes */
|
||||
uint16_t _payload_size; /* payload size in bytes */
|
||||
|
||||
/*****************************************************
|
||||
** 'payload' must be the last member of this class **
|
||||
*****************************************************/
|
||||
|
||||
char payload[0];
|
||||
|
||||
public:
|
||||
|
||||
Packet_base(size_t size)
|
||||
:
|
||||
Ethernet_frame(),
|
||||
Ipv4_packet(),
|
||||
_payload_size(size)
|
||||
{ }
|
||||
|
||||
void const * base() const { return &payload; }
|
||||
|
||||
/**
|
||||
* Return type of the packet
|
||||
*/
|
||||
Type type() const { return _type; }
|
||||
|
||||
/**
|
||||
* Return size of the packet
|
||||
*/
|
||||
size_t size() const { return _payload_size + sizeof(Packet_base); }
|
||||
|
||||
/**
|
||||
* Return content_size of the packet
|
||||
*/
|
||||
size_t content_size() const { return _content_size; }
|
||||
|
||||
/**
|
||||
* Return offset of the packet
|
||||
*/
|
||||
size_t offset() const { return _offset; }
|
||||
|
||||
/**
|
||||
* Return module_name of the packet
|
||||
*/
|
||||
char* module_name() { return _module_name; }
|
||||
|
||||
/**
|
||||
* Set payload size of the packet
|
||||
*/
|
||||
void payload_size(Genode::size_t payload_size)
|
||||
{
|
||||
_payload_size = payload_size;
|
||||
Ipv4_packet::total_length(size() - sizeof(Ethernet_frame));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return payload size of the packet
|
||||
*/
|
||||
size_t payload_size() const { return _payload_size; }
|
||||
|
||||
/**
|
||||
* Return address of the payload
|
||||
*/
|
||||
void *addr() { return payload; }
|
||||
|
||||
void prepare_ethernet(const Mac_address &src, const Mac_address &dst=Ethernet_frame::broadcast())
|
||||
{
|
||||
Ethernet_frame::src(src);
|
||||
Ethernet_frame::dst(dst);
|
||||
Ethernet_frame::type(Ethernet_frame::Type::IPV4);
|
||||
}
|
||||
|
||||
void prepare_ipv4(const Ipv4_address &src, const Ipv4_address &dst=Ipv4_packet::broadcast())
|
||||
{
|
||||
Ipv4_packet::version(4);
|
||||
Ipv4_packet::header_length(5);
|
||||
Ipv4_packet::time_to_live(10);
|
||||
Ipv4_packet::src(src);
|
||||
Ipv4_packet::dst(dst);
|
||||
Ipv4_packet::total_length(size() - sizeof(Ethernet_frame));
|
||||
}
|
||||
|
||||
void set_checksums()
|
||||
{
|
||||
Ipv4_packet::update_checksum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Placement new.
|
||||
*/
|
||||
void * operator new(__SIZE_TYPE__ size, void* addr) { return addr; }
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
class Remote_rom::SignalPacket : public Packet_base
|
||||
{
|
||||
public:
|
||||
SignalPacket() : Packet_base(0)
|
||||
{ }
|
||||
|
||||
void prepare(const char *module)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
_type = SIGNAL;
|
||||
_payload_size = 0;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
class Remote_rom::UpdatePacket : public Packet_base
|
||||
{
|
||||
public:
|
||||
UpdatePacket() : Packet_base(0)
|
||||
{ }
|
||||
|
||||
void prepare(const char *module)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
_type = UPDATE;
|
||||
_payload_size = 0;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
class Remote_rom::DataPacket : public Packet_base
|
||||
{
|
||||
public:
|
||||
enum { MAX_PAYLOAD_SIZE = 1024 };
|
||||
|
||||
char payload[MAX_PAYLOAD_SIZE];
|
||||
|
||||
DataPacket() : Packet_base(MAX_PAYLOAD_SIZE)
|
||||
{ }
|
||||
|
||||
void prepare(const char* module, size_t offset, size_t content_size)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
|
||||
_payload_size = MAX_PAYLOAD_SIZE;
|
||||
_offset = offset;
|
||||
_content_size = content_size;
|
||||
|
||||
if (offset == 0)
|
||||
_type = DATA;
|
||||
else
|
||||
_type = DATA_CONT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return packet size for given payload
|
||||
*/
|
||||
static size_t packet_size(size_t payload) { return sizeof(Packet_base) + Genode::min(payload, MAX_PAYLOAD_SIZE); }
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
template <class HANDLER>
|
||||
class Remote_rom::Backend_base
|
||||
{
|
||||
protected:
|
||||
enum {
|
||||
PACKET_SIZE = 1024,
|
||||
BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE
|
||||
};
|
||||
|
||||
class Rx_thread : public Genode::Thread
|
||||
{
|
||||
protected:
|
||||
Ipv4_address &_accept_ip;
|
||||
Nic::Connection &_nic;
|
||||
HANDLER &_handler;
|
||||
|
||||
Genode::Signal_receiver _sig_rec;
|
||||
Genode::Signal_dispatcher<Rx_thread> _link_state_dispatcher;
|
||||
Genode::Signal_dispatcher<Rx_thread> _rx_packet_avail_dispatcher;
|
||||
Genode::Signal_dispatcher<Rx_thread> _rx_ready_to_ack_dispatcher;
|
||||
|
||||
void _handle_rx_packet_avail(unsigned)
|
||||
{
|
||||
while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) {
|
||||
Packet_descriptor _rx_packet = _nic.rx()->get_packet();
|
||||
|
||||
char *content = _nic.rx()->packet_content(_rx_packet);
|
||||
|
||||
/* check IP */
|
||||
Ipv4_packet &ip_packet = *(Packet_base*)content;
|
||||
if (_accept_ip == Ipv4_packet::broadcast() || _accept_ip == ip_packet.dst())
|
||||
_handler.receive(*(Packet_base*)content);
|
||||
|
||||
_nic.rx()->acknowledge_packet(_rx_packet);
|
||||
}
|
||||
}
|
||||
|
||||
void _handle_rx_ready_to_ack(unsigned) { _handle_rx_packet_avail(0); }
|
||||
|
||||
void _handle_link_state(unsigned)
|
||||
{
|
||||
Genode::log("link state changed");
|
||||
}
|
||||
|
||||
public:
|
||||
Rx_thread(Nic::Connection &nic, HANDLER &handler, Ipv4_address &ip)
|
||||
: Genode::Thread(Weight::DEFAULT_WEIGHT, "backend_nic_rx", 8192),
|
||||
_accept_ip(ip),
|
||||
_nic(nic), _handler(handler),
|
||||
_link_state_dispatcher(_sig_rec, *this, &Rx_thread::_handle_link_state),
|
||||
_rx_packet_avail_dispatcher(_sig_rec, *this, &Rx_thread::_handle_rx_packet_avail),
|
||||
_rx_ready_to_ack_dispatcher(_sig_rec, *this, &Rx_thread::_handle_rx_ready_to_ack)
|
||||
{
|
||||
_nic.link_state_sigh(_link_state_dispatcher);
|
||||
_nic.rx_channel()->sigh_packet_avail(_rx_packet_avail_dispatcher);
|
||||
_nic.rx_channel()->sigh_ready_to_ack(_rx_ready_to_ack_dispatcher);
|
||||
}
|
||||
|
||||
void entry()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
Genode::Signal sig = _sig_rec.wait_for_signal();
|
||||
int num = sig.num();
|
||||
|
||||
Genode::Signal_dispatcher_base *dispatcher;
|
||||
dispatcher = dynamic_cast<Genode::Signal_dispatcher_base *>(sig.context());
|
||||
dispatcher->dispatch(num);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Nic::Packet_allocator _tx_block_alloc;
|
||||
Nic::Connection _nic;
|
||||
Rx_thread _rx_thread;
|
||||
Mac_address _mac_address;
|
||||
Ipv4_address _src_ip;
|
||||
Ipv4_address _accept_ip;
|
||||
Ipv4_address _dst_ip;
|
||||
|
||||
protected:
|
||||
void _tx_ack(bool block = false)
|
||||
{
|
||||
/* check for acknowledgements */
|
||||
while (_nic.tx()->ack_avail() || block) {
|
||||
Nic::Packet_descriptor acked_packet = _nic.tx()->get_acked_packet();
|
||||
_nic.tx()->release_packet(acked_packet);
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Backend_base(Genode::Env &env, Genode::Allocator &alloc, HANDLER &handler)
|
||||
:
|
||||
_tx_block_alloc(&alloc), _nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE),
|
||||
_rx_thread(_nic, handler, _accept_ip)
|
||||
{
|
||||
/* start dispatcher thread */
|
||||
_rx_thread.start();
|
||||
|
||||
/* store mac address */
|
||||
_mac_address = _nic.mac_address();
|
||||
|
||||
Genode::Attached_rom_dataspace config = {env, "config"};
|
||||
|
||||
try {
|
||||
char ip_string[15];
|
||||
Genode::Xml_node remoterom = config.xml().sub_node("remote_rom");
|
||||
remoterom.attribute("src").value(ip_string, sizeof(ip_string));
|
||||
_src_ip = Ipv4_packet::ip_from_string(ip_string);
|
||||
|
||||
remoterom.attribute("dst").value(ip_string, sizeof(ip_string));
|
||||
_dst_ip = Ipv4_packet::ip_from_string(ip_string);
|
||||
|
||||
_accept_ip = _src_ip;
|
||||
} catch (...) {
|
||||
Genode::warning("No IP configured, falling back to broadcast mode!");
|
||||
_src_ip = Ipv4_packet::current();
|
||||
_dst_ip = Ipv4_packet::broadcast();
|
||||
_accept_ip = Ipv4_packet::broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
Nic::Packet_descriptor alloc_tx_packet(Genode::size_t size)
|
||||
{
|
||||
while (true) {
|
||||
try {
|
||||
Nic::Packet_descriptor packet = _nic.tx()->alloc_packet(size);
|
||||
return packet;
|
||||
} catch(Nic::Session::Tx::Source::Packet_alloc_failed) {
|
||||
/* packet allocator exhausted, wait for acknowledgements */
|
||||
_tx_ack(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void submit_tx_packet(Nic::Packet_descriptor packet)
|
||||
{
|
||||
_nic.tx()->submit_packet(packet);
|
||||
/* check for acknowledgements */
|
||||
_tx_ack();
|
||||
}
|
||||
};
|
||||
|
||||
class Remote_rom::Backend_server : public Backend_server_base, public Backend_base<Backend_server>
|
||||
{
|
||||
private:
|
||||
Rom_forwarder_base *_forwarder;
|
||||
|
||||
void send_data()
|
||||
{
|
||||
if (!_forwarder) return;
|
||||
|
||||
size_t offset = 0;
|
||||
size_t size = _forwarder->content_size();
|
||||
while (offset < size)
|
||||
{
|
||||
/* create and transmit packet via NIC session */
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(DataPacket::packet_size(size));
|
||||
DataPacket *packet = new (_nic.tx()->packet_content(pd)) DataPacket();
|
||||
|
||||
packet->prepare_ethernet(_mac_address, Ethernet_frame::broadcast());
|
||||
packet->prepare_ipv4(_src_ip, _dst_ip);
|
||||
packet->prepare(_forwarder->module_name(), offset, size);
|
||||
|
||||
packet->payload_size(_forwarder->transfer_content((char*)packet->addr(), DataPacket::MAX_PAYLOAD_SIZE, offset));
|
||||
packet->set_checksums();
|
||||
|
||||
submit_tx_packet(pd);
|
||||
|
||||
offset += packet->payload_size();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Backend_server(Genode::Env &env, Genode::Allocator &alloc) : Backend_base(env, alloc, *this), _forwarder(nullptr)
|
||||
{ }
|
||||
|
||||
void register_forwarder(Rom_forwarder_base *forwarder)
|
||||
{
|
||||
_forwarder = forwarder;
|
||||
}
|
||||
|
||||
void send_update()
|
||||
{
|
||||
if (!_forwarder) return;
|
||||
|
||||
/* create and transmit packet via NIC session */
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(sizeof(SignalPacket));
|
||||
SignalPacket *packet = new (_nic.tx()->packet_content(pd)) SignalPacket();
|
||||
|
||||
packet->prepare_ethernet(_mac_address);
|
||||
packet->prepare_ipv4(_src_ip, _dst_ip);
|
||||
packet->prepare(_forwarder->module_name());
|
||||
packet->set_checksums();
|
||||
|
||||
submit_tx_packet(pd);
|
||||
}
|
||||
|
||||
void receive(Packet_base &packet)
|
||||
{
|
||||
switch (packet.type())
|
||||
{
|
||||
case Packet_base::UPDATE:
|
||||
if (verbose)
|
||||
Genode::log("receiving UPDATE (", Cstring(packet.module_name()), ") packet");
|
||||
|
||||
if (!_forwarder)
|
||||
return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _forwarder->module_name()))
|
||||
return;
|
||||
|
||||
/* TODO (optional) dont send data within Rx_Thread's context */
|
||||
send_data();
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Remote_rom::Backend_client : public Backend_client_base, public Backend_base<Backend_client>
|
||||
{
|
||||
private:
|
||||
Rom_receiver_base *_receiver;
|
||||
char *_write_ptr;
|
||||
size_t _buf_size;
|
||||
|
||||
|
||||
void write(char *data, size_t offset, size_t size)
|
||||
{
|
||||
if (!_write_ptr) return;
|
||||
|
||||
size_t const len = Genode::min(size, _buf_size-offset);
|
||||
Genode::memcpy(_write_ptr+offset, data, len);
|
||||
|
||||
if (offset + len >= _buf_size)
|
||||
_receiver->commit_new_content();
|
||||
}
|
||||
|
||||
public:
|
||||
Backend_client(Genode::Env &env, Genode::Allocator &alloc) : Backend_base(env, alloc, *this), _receiver(nullptr), _write_ptr(nullptr), _buf_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
void register_receiver(Rom_receiver_base *receiver)
|
||||
{
|
||||
/* TODO support multiple receivers (ROM names) */
|
||||
_receiver = receiver;
|
||||
|
||||
/* FIXME request update on startup (occasionally triggers invalid signal-context capability) */
|
||||
// if (_receiver)
|
||||
// update(_receiver->module_name());
|
||||
}
|
||||
|
||||
|
||||
void update(const char* module_name)
|
||||
{
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(module_name, _receiver->module_name()))
|
||||
return;
|
||||
|
||||
/* create and transmit packet via NIC session */
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(sizeof(UpdatePacket));
|
||||
UpdatePacket *packet = (UpdatePacket*)_nic.tx()->packet_content(pd);
|
||||
|
||||
packet->prepare_ethernet(_mac_address);
|
||||
packet->prepare_ipv4(_src_ip, _dst_ip);
|
||||
packet->prepare(_receiver->module_name());
|
||||
packet->set_checksums();
|
||||
|
||||
submit_tx_packet(pd);
|
||||
}
|
||||
|
||||
void receive(Packet_base &packet)
|
||||
{
|
||||
switch (packet.type())
|
||||
{
|
||||
case Packet_base::SIGNAL:
|
||||
if (verbose)
|
||||
Genode::log("receiving SIGNAL(", Cstring(packet.module_name()), ") packet");
|
||||
|
||||
/* send update request */
|
||||
update(packet.module_name());
|
||||
|
||||
break;
|
||||
case Packet_base::DATA:
|
||||
if (verbose)
|
||||
Genode::log("receiving DATA(", Cstring(packet.module_name()), ") packet");
|
||||
|
||||
/* write into buffer */
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _receiver->module_name()))
|
||||
return;
|
||||
|
||||
_write_ptr = _receiver->start_new_content(packet.content_size());
|
||||
_buf_size = (_write_ptr) ? packet.content_size() : 0;
|
||||
|
||||
write((char*)packet.addr(), packet.offset(), packet.payload_size());
|
||||
|
||||
break;
|
||||
case Packet_base::DATA_CONT:
|
||||
if (verbose)
|
||||
Genode::log("receiving DATA_CONT(", Cstring(packet.module_name()), ") packet");
|
||||
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _receiver->module_name()))
|
||||
return;
|
||||
|
||||
/* write into buffer */
|
||||
write((char*)packet.addr(), packet.offset(), packet.payload_size());
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Remote_rom::Backend_server_base &Remote_rom::backend_init_server(Genode::Env &env, Genode::Allocator &alloc)
|
||||
{
|
||||
static Backend_server backend(env, alloc);
|
||||
return backend;
|
||||
}
|
||||
|
||||
Remote_rom::Backend_client_base &Remote_rom::backend_init_client(Genode::Env &env, Genode::Allocator &alloc)
|
||||
{
|
||||
static Backend_client backend(env, alloc);
|
||||
return backend;
|
||||
}
|
||||
195
src/lib/remote_rom/backend/nic_ip/base.h
Normal file
195
src/lib/remote_rom/backend/nic_ip/base.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* \brief Common base for client and server
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-18
|
||||
*/
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/log.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/connection.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/ipv4.h>
|
||||
|
||||
#include <packet.h>
|
||||
|
||||
#ifndef __INCLUDE__REMOTE_ROM__BASE_H_
|
||||
#define __INCLUDE__REMOTE_ROM__BASE_H_
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::Packet_descriptor;
|
||||
using Genode::env;
|
||||
using Net::Ethernet_frame;
|
||||
using Net::Ipv4_packet;
|
||||
using Net::Mac_address;
|
||||
using Net::Ipv4_address;
|
||||
using Net::Size_guard;
|
||||
|
||||
class Backend_base;
|
||||
};
|
||||
|
||||
|
||||
class Remote_rom::Backend_base : public Genode::Interface
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Signal_handler<Backend_base> _link_state_handler;
|
||||
Genode::Signal_handler<Backend_base> _rx_packet_handler;
|
||||
|
||||
void _handle_rx_packet()
|
||||
{
|
||||
while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) {
|
||||
Packet_descriptor _rx_packet = _nic.rx()->get_packet();
|
||||
|
||||
char *content = _nic.rx()->packet_content(_rx_packet);
|
||||
Size_guard edguard(_rx_packet.size());
|
||||
Ethernet_frame ð = Ethernet_frame::cast_from(content, edguard);
|
||||
|
||||
/* check IP */
|
||||
Ipv4_packet &ip_packet = eth.data<Ipv4_packet>(edguard);
|
||||
if (_accept_ip == Ipv4_packet::broadcast()
|
||||
|| _accept_ip == ip_packet.dst())
|
||||
receive(ip_packet.data<Packet>(edguard), edguard);
|
||||
|
||||
_nic.rx()->acknowledge_packet(_rx_packet);
|
||||
}
|
||||
}
|
||||
|
||||
void _handle_link_state()
|
||||
{
|
||||
Genode::log("link state changed");
|
||||
}
|
||||
|
||||
void _tx_ack(bool block = false)
|
||||
{
|
||||
/* check for acknowledgements */
|
||||
while (_nic.tx()->ack_avail() || block) {
|
||||
Nic::Packet_descriptor acked_packet = _nic.tx()->get_acked_packet();
|
||||
_nic.tx()->release_packet(acked_packet);
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
PACKET_SIZE = 1024,
|
||||
BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE
|
||||
};
|
||||
|
||||
const bool _verbose = false;
|
||||
Nic::Packet_allocator _tx_block_alloc;
|
||||
Nic::Connection _nic;
|
||||
Mac_address _mac_address;
|
||||
Ipv4_address _src_ip;
|
||||
Ipv4_address _accept_ip;
|
||||
Ipv4_address _dst_ip;
|
||||
|
||||
/**
|
||||
* Handle accepted network packet from the other side
|
||||
*/
|
||||
virtual void receive(Packet &packet, Size_guard &) = 0;
|
||||
|
||||
Ipv4_packet &_prepare_upper_layers(void *base, Size_guard &size_guard)
|
||||
{
|
||||
Ethernet_frame ð = Ethernet_frame::construct_at(base, size_guard);
|
||||
eth.src(_mac_address);
|
||||
eth.dst(Ethernet_frame::broadcast());
|
||||
eth.type(Ethernet_frame::Type::IPV4);
|
||||
|
||||
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
|
||||
ip.version(4);
|
||||
ip.header_length(5);
|
||||
ip.time_to_live(10);
|
||||
ip.src(_src_ip);
|
||||
ip.dst(_dst_ip);
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
size_t _upper_layer_size(size_t size)
|
||||
{
|
||||
return sizeof(Ethernet_frame) + sizeof(Ipv4_packet) + size;
|
||||
}
|
||||
|
||||
void _finish_ipv4(Ipv4_packet &ip, size_t payload)
|
||||
{
|
||||
ip.total_length(sizeof(ip) + payload);
|
||||
ip.update_checksum();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void _transmit_notification_packet(Packet::Type type, T *frontend)
|
||||
{
|
||||
size_t frame_size = _upper_layer_size(sizeof(Packet));
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(frame_size);
|
||||
Size_guard size_guard(pd.size());
|
||||
|
||||
char *content = _nic.tx()->packet_content(pd);
|
||||
Ipv4_packet &ip = _prepare_upper_layers(content, size_guard);
|
||||
Packet &pak = ip.construct_at_data<Packet>(size_guard);
|
||||
pak.type(type);
|
||||
pak.module_name(frontend->module_name());
|
||||
_finish_ipv4(ip, sizeof(Packet));
|
||||
|
||||
submit_tx_packet(pd);
|
||||
}
|
||||
|
||||
explicit Backend_base(Genode::Env &env, Genode::Allocator &alloc)
|
||||
:
|
||||
_link_state_handler(env.ep(), *this, &Backend_base::_handle_link_state),
|
||||
_rx_packet_handler(env.ep(), *this, &Backend_base::_handle_rx_packet),
|
||||
|
||||
_tx_block_alloc(&alloc),
|
||||
_nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE),
|
||||
|
||||
_mac_address(_nic.mac_address()),
|
||||
_src_ip(Ipv4_packet::current()),
|
||||
_accept_ip(Ipv4_packet::broadcast()),
|
||||
_dst_ip(Ipv4_packet::broadcast())
|
||||
{
|
||||
_nic.link_state_sigh(_link_state_handler);
|
||||
_nic.rx_channel()->sigh_packet_avail(_rx_packet_handler);
|
||||
_nic.rx_channel()->sigh_ready_to_ack(_rx_packet_handler);
|
||||
|
||||
Genode::Attached_rom_dataspace config = {env, "config"};
|
||||
try {
|
||||
char ip_string[15];
|
||||
Genode::Xml_node remoterom = config.xml().sub_node("remote_rom");
|
||||
remoterom.attribute("src").value(ip_string, sizeof(ip_string));
|
||||
_src_ip = Ipv4_packet::ip_from_string(ip_string);
|
||||
|
||||
remoterom.attribute("dst").value(ip_string, sizeof(ip_string));
|
||||
_dst_ip = Ipv4_packet::ip_from_string(ip_string);
|
||||
|
||||
_accept_ip = _src_ip;
|
||||
} catch (...) {
|
||||
Genode::warning("No IP configured, falling back to broadcast mode!");
|
||||
}
|
||||
}
|
||||
|
||||
Nic::Packet_descriptor alloc_tx_packet(Genode::size_t size)
|
||||
{
|
||||
while (true) {
|
||||
try {
|
||||
Nic::Packet_descriptor packet = _nic.tx()->alloc_packet(size);
|
||||
return packet;
|
||||
} catch(Nic::Session::Tx::Source::Packet_alloc_failed) {
|
||||
/* packet allocator exhausted, wait for acknowledgements */
|
||||
_tx_ack(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void submit_tx_packet(Nic::Packet_descriptor packet)
|
||||
{
|
||||
_nic.tx()->submit_packet(packet);
|
||||
/* check for acknowledgements */
|
||||
_tx_ack();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
131
src/lib/remote_rom/backend/nic_ip/client.cc
Normal file
131
src/lib/remote_rom/backend/nic_ip/client.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* \brief Client implementation
|
||||
* \author Johannes Schlatow
|
||||
* \date 2018-11-06
|
||||
*/
|
||||
|
||||
#include <backend_base.h>
|
||||
#include <base.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::Cstring;
|
||||
|
||||
struct Backend_client;
|
||||
};
|
||||
|
||||
class Remote_rom::Backend_client :
|
||||
public Backend_client_base,
|
||||
public Backend_base
|
||||
{
|
||||
private:
|
||||
|
||||
Rom_receiver_base *_receiver;
|
||||
char *_write_ptr;
|
||||
size_t _buf_size;
|
||||
|
||||
Backend_client(Backend_client &);
|
||||
Backend_client &operator= (Backend_client &);
|
||||
|
||||
void write(const void *data, size_t offset, size_t size)
|
||||
{
|
||||
if (!_write_ptr) return;
|
||||
|
||||
|
||||
size_t const len = Genode::min(size, _buf_size-offset);
|
||||
Genode::memcpy(_write_ptr+offset, data, len);
|
||||
|
||||
if (offset + len >= _buf_size)
|
||||
_receiver->commit_new_content();
|
||||
}
|
||||
|
||||
|
||||
void update(const char* module_name)
|
||||
{
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(module_name, _receiver->module_name()))
|
||||
return;
|
||||
|
||||
_transmit_notification_packet(Packet::UPDATE, _receiver);
|
||||
}
|
||||
|
||||
|
||||
void receive(Packet &packet, Size_guard &size_guard)
|
||||
{
|
||||
switch (packet.type())
|
||||
{
|
||||
case Packet::SIGNAL:
|
||||
if (_verbose)
|
||||
Genode::log("receiving SIGNAL(",
|
||||
Cstring(packet.module_name()),
|
||||
") packet");
|
||||
|
||||
/* send update request */
|
||||
update(packet.module_name());
|
||||
|
||||
break;
|
||||
case Packet::DATA:
|
||||
{
|
||||
if (_verbose)
|
||||
Genode::log("receiving DATA(",
|
||||
Cstring(packet.module_name()),
|
||||
") packet");
|
||||
|
||||
/* write into buffer */
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _receiver->module_name()))
|
||||
return;
|
||||
|
||||
const DataPacket &data = packet.data<DataPacket>(size_guard);
|
||||
size_guard.consume_head(data.payload_size());
|
||||
|
||||
if (!data.offset()) {
|
||||
_write_ptr = _receiver->start_new_content(data.content_size());
|
||||
_buf_size = (_write_ptr) ? data.content_size() : 0;
|
||||
}
|
||||
|
||||
write(data.addr(), data.offset(), data.payload_size());
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Backend_client(Genode::Env &env, Genode::Allocator &alloc) :
|
||||
Backend_base(env, alloc),
|
||||
_receiver(nullptr), _write_ptr(nullptr),
|
||||
_buf_size(0)
|
||||
{ }
|
||||
|
||||
|
||||
void register_receiver(Rom_receiver_base *receiver)
|
||||
{
|
||||
/* TODO support multiple receivers (ROM names) */
|
||||
_receiver = receiver;
|
||||
|
||||
/*
|
||||
* FIXME request update on startup
|
||||
* (occasionally triggers invalid signal-context capability)
|
||||
* */
|
||||
// if (_receiver)
|
||||
// update(_receiver->module_name());
|
||||
}
|
||||
};
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::Env;
|
||||
using Genode::Allocator;
|
||||
|
||||
Backend_client_base &backend_init_client(Env &env, Allocator &alloc)
|
||||
{
|
||||
static Backend_client backend(env, alloc);
|
||||
return backend;
|
||||
}
|
||||
};
|
||||
143
src/lib/remote_rom/backend/nic_ip/packet.h
Normal file
143
src/lib/remote_rom/backend/nic_ip/packet.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* \brief Packet format we use for inter-system communication
|
||||
* \author Johannes Schlatow
|
||||
* \date 2018-11-05
|
||||
*/
|
||||
|
||||
#include <util/construct_at.h>
|
||||
#include <util/string.h>
|
||||
#include <net/size_guard.h>
|
||||
|
||||
#ifndef __INCLUDE__REMOTE_ROM__PACKET_H_
|
||||
#define __INCLUDE__REMOTE_ROM__PACKET_H_
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::size_t;
|
||||
using Genode::uint16_t;
|
||||
using Genode::uint32_t;
|
||||
|
||||
struct Packet;
|
||||
struct DataPacket;
|
||||
}
|
||||
|
||||
class Remote_rom::Packet
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
MAX_NAME_LEN = 64 /* maximum length of the module name */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SIGNAL = 1, /* signal that ROM content has changed */
|
||||
UPDATE = 2, /* request transmission of updated content */
|
||||
DATA = 3, /* data packet */
|
||||
} Type;
|
||||
|
||||
private:
|
||||
char _module_name[MAX_NAME_LEN]; /* the ROM module name */
|
||||
Type _type; /* packet type */
|
||||
|
||||
/*****************************************************
|
||||
** 'payload' must be the last member of this class **
|
||||
*****************************************************/
|
||||
|
||||
char payload[0];
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return type of the packet
|
||||
*/
|
||||
Type type() const { return _type; }
|
||||
|
||||
/**
|
||||
* Return module_name of the packet
|
||||
*/
|
||||
const char *module_name() { return _module_name; }
|
||||
|
||||
void type(Type type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
void module_name(const char *module)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T const &data(Net::Size_guard &size_guard) const
|
||||
{
|
||||
size_guard.consume_head(sizeof(T));
|
||||
return *(T const *)(payload);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T &construct_at_data(Net::Size_guard &size_guard)
|
||||
{
|
||||
size_guard.consume_head(sizeof(T));
|
||||
return *Genode::construct_at<T>(payload);
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
class Remote_rom::DataPacket
|
||||
{
|
||||
public:
|
||||
static const size_t MAX_PAYLOAD_SIZE = 1024;
|
||||
|
||||
private:
|
||||
uint32_t _content_size; /* ROM content size in bytes */
|
||||
uint32_t _offset; /* offset in bytes */
|
||||
uint16_t _payload_size; /* payload size in bytes */
|
||||
|
||||
char payload[0];
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return size of the packet
|
||||
*/
|
||||
size_t size() const { return _payload_size + sizeof(*this); }
|
||||
|
||||
/**
|
||||
* Return content_size of the packet
|
||||
*/
|
||||
size_t content_size() const { return _content_size; }
|
||||
|
||||
/**
|
||||
* Return offset of the packet
|
||||
*/
|
||||
size_t offset() const { return _offset; }
|
||||
|
||||
void content_size(size_t size) { _content_size = size; }
|
||||
void offset(size_t offset) { _offset = offset; }
|
||||
|
||||
/**
|
||||
* Set payload size of the packet
|
||||
*/
|
||||
void payload_size(Genode::size_t payload_size)
|
||||
{
|
||||
_payload_size = payload_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return payload size of the packet
|
||||
*/
|
||||
size_t payload_size() const { return _payload_size; }
|
||||
|
||||
/**
|
||||
* Return address of the payload
|
||||
*/
|
||||
void *addr() { return payload; }
|
||||
const void *addr() const { return payload; }
|
||||
|
||||
/**
|
||||
* Return packet size for given payload
|
||||
*/
|
||||
static size_t packet_size(size_t payload) {
|
||||
return sizeof(DataPacket) + Genode::min(payload, MAX_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
||||
119
src/lib/remote_rom/backend/nic_ip/server.cc
Normal file
119
src/lib/remote_rom/backend/nic_ip/server.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* \brief Server implementation
|
||||
* \author Johannes Schlatow
|
||||
* \date 2018-11-06
|
||||
*/
|
||||
|
||||
#include <backend_base.h>
|
||||
#include <base.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::Cstring;
|
||||
|
||||
struct Backend_server;
|
||||
};
|
||||
|
||||
class Remote_rom::Backend_server :
|
||||
public Backend_server_base,
|
||||
public Backend_base
|
||||
{
|
||||
private:
|
||||
|
||||
Rom_forwarder_base *_forwarder;
|
||||
|
||||
Backend_server(Backend_server &);
|
||||
Backend_server &operator= (Backend_server &);
|
||||
|
||||
void send_data()
|
||||
{
|
||||
if (!_forwarder) return;
|
||||
|
||||
size_t offset = 0;
|
||||
size_t size = _forwarder->content_size();
|
||||
while (offset < size)
|
||||
{
|
||||
/* create and transmit packet via NIC session */
|
||||
size_t max_size = _upper_layer_size(sizeof(Packet)
|
||||
+ DataPacket::packet_size(size));
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(max_size);
|
||||
Size_guard size_guard(pd.size());
|
||||
|
||||
char *content = _nic.tx()->packet_content(pd);
|
||||
Ipv4_packet &ip = _prepare_upper_layers(content, size_guard);
|
||||
Packet &pak = ip.construct_at_data<Packet>(size_guard);
|
||||
pak.type(Packet::DATA);
|
||||
pak.module_name(_forwarder->module_name());
|
||||
|
||||
DataPacket &data = pak.construct_at_data<DataPacket>(size_guard);
|
||||
data.offset(offset);
|
||||
data.content_size(size);
|
||||
|
||||
const size_t max = DataPacket::MAX_PAYLOAD_SIZE;
|
||||
data.payload_size(_forwarder->transfer_content((char*)data.addr(),
|
||||
max,
|
||||
offset));
|
||||
_finish_ipv4(ip, sizeof(Packet) + data.size());
|
||||
|
||||
submit_tx_packet(pd);
|
||||
|
||||
offset += data.payload_size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void receive(Packet &packet, Size_guard &)
|
||||
{
|
||||
switch (packet.type())
|
||||
{
|
||||
case Packet::UPDATE:
|
||||
if (_verbose)
|
||||
Genode::log("receiving UPDATE (",
|
||||
Cstring(packet.module_name()),
|
||||
") packet");
|
||||
|
||||
if (!_forwarder)
|
||||
return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _forwarder->module_name()))
|
||||
return;
|
||||
|
||||
send_data();
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Backend_server(Genode::Env &env, Genode::Allocator &alloc) :
|
||||
Backend_base(env, alloc),
|
||||
_forwarder(nullptr)
|
||||
{ }
|
||||
|
||||
|
||||
void register_forwarder(Rom_forwarder_base *forwarder)
|
||||
{
|
||||
_forwarder = forwarder;
|
||||
}
|
||||
|
||||
|
||||
void send_update()
|
||||
{
|
||||
if (!_forwarder) return;
|
||||
_transmit_notification_packet(Packet::SIGNAL, _forwarder);
|
||||
}
|
||||
};
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::Env;
|
||||
using Genode::Allocator;
|
||||
|
||||
Backend_server_base &backend_init_server(Env &env, Allocator &alloc)
|
||||
{
|
||||
static Backend_server backend(env, alloc);
|
||||
return backend;
|
||||
}
|
||||
};
|
||||
@@ -1,32 +1,35 @@
|
||||
The remote ROM allows providing ROM services over a network or similar communication
|
||||
medium and thus implements publisher/subscriber communication in a distributed system.
|
||||
The remote ROM allows providing ROM services over a network or similar
|
||||
communication medium and thus implements publisher/subscriber communication in
|
||||
a distributed system.
|
||||
|
||||
The remote_rom server connects to a local ROM service and provides a remote ROM service
|
||||
via the specified backend. The remote_rom client connects to a remote ROM service via
|
||||
the specified backend and provides a ROM service via local RPC.
|
||||
The remote_rom server connects to a local ROM service and provides a remote ROM
|
||||
service via the specified backend. The remote_rom client connects to a remote
|
||||
ROM service via the specified backend and provides a ROM service via local RPC.
|
||||
|
||||
Backends
|
||||
--------
|
||||
|
||||
The remote_rom can be compiled with one of multiple back ends that use different session
|
||||
interfaces or libraries to forward and receive the packets. By exchanging the backend,
|
||||
we can also easily change the publication strategy (e.g., notification+polling vs. multicast).
|
||||
Furthermore, a back end is responsible for access control and optionally allows the
|
||||
specification of a policy for this.
|
||||
The remote_rom can be compiled with one of multiple back ends that use
|
||||
different session interfaces or libraries to forward and receive the packets.
|
||||
By exchanging the backend, we can also easily change the publication strategy
|
||||
(e.g., notification+polling vs. multicast). Furthermore, a back end is
|
||||
responsible for access control and optionally allows the specification of a
|
||||
policy for this.
|
||||
|
||||
:'nic_ip':
|
||||
This back end uses a Nic_session to transmit network packets with IPv4 headers.
|
||||
This back end uses a Nic_session to transmit network packets with IPv4
|
||||
headers.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Both the client and the server evaluate the '<remote_rom>' node of their config.
|
||||
The _name_ attribute specifies the ROMs module name. The '<remote_rom>' node may
|
||||
further contain a '<default>' node that can be used to populate the ROM with a default
|
||||
content.
|
||||
Both the client and the server evaluate the '<remote_rom>' node of their
|
||||
config. The _name_ attribute specifies the ROMs module name. The
|
||||
'<remote_rom>' node may further contain a '<default>' node that can be used to
|
||||
populate the ROM with a default content.
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
For an example that illustrates the use of these components, please refer to the
|
||||
_run/remote_rom_backend_nic_ip.run_ script.
|
||||
For an example that illustrates the use of these components, please refer to
|
||||
the _run/remote_rom_backend_nic_ip.run_ script.
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
include $(PRG_DIR)/../target.inc
|
||||
include $(PRG_DIR)/../../../client/target.inc
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
include $(PRG_DIR)/../target.inc
|
||||
include $(PRG_DIR)/../../../server/target.inc
|
||||
|
||||
CC_CXX_WARN_STRICT =
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* \date 2016-02-15
|
||||
*
|
||||
* Usage scenario:
|
||||
* __________ ________________ _________________ __________
|
||||
* | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client |
|
||||
* | | | server | | client | | |
|
||||
* ---------- ---------------- ----------------- ----------
|
||||
* __________ ______________ ______________ __________
|
||||
* | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client |
|
||||
* | | | server | | client | | |
|
||||
* ---------- -------------- -------------- ----------
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -44,21 +44,23 @@ namespace Remote_rom {
|
||||
struct Main;
|
||||
struct Read_buffer;
|
||||
|
||||
typedef Genode::List<Session_component> Session_list;
|
||||
typedef Genode::List_element<Session_component> Session_element;
|
||||
typedef Genode::List<Session_element> Session_list;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface used by the sessions to obtain the ROM data received from the remote server
|
||||
* Interface used by the sessions to obtain the ROM data received from the
|
||||
* remote server
|
||||
*/
|
||||
struct Remote_rom::Read_buffer
|
||||
struct Remote_rom::Read_buffer : Genode::Interface
|
||||
{
|
||||
virtual size_t content_size() const = 0;
|
||||
virtual size_t export_content(char *dst, size_t dst_len) const = 0;
|
||||
};
|
||||
|
||||
class Remote_rom::Session_component : public Genode::Rpc_object<Genode::Rom_session, Remote_rom::Session_component>,
|
||||
public Session_list::Element
|
||||
class Remote_rom::Session_component :
|
||||
public Genode::Rpc_object<Genode::Rom_session, Session_component>
|
||||
{
|
||||
private:
|
||||
Genode::Env &_env;
|
||||
@@ -68,6 +70,7 @@ class Remote_rom::Session_component : public Genode::Rpc_object<Genode::Rom_sess
|
||||
Read_buffer const &_buffer;
|
||||
|
||||
Session_list &_sessions;
|
||||
Session_element _element;
|
||||
|
||||
Constructible<Genode::Attached_ram_dataspace> _ram_ds;
|
||||
|
||||
@@ -75,14 +78,16 @@ class Remote_rom::Session_component : public Genode::Rpc_object<Genode::Rom_sess
|
||||
|
||||
static int version() { return 1; }
|
||||
|
||||
Session_component(Genode::Env &env, Session_list &sessions, Read_buffer const &buffer)
|
||||
Session_component(Genode::Env &env, Session_list &sessions,
|
||||
Read_buffer const &buffer)
|
||||
:
|
||||
_env(env), _buffer(buffer), _sessions(sessions)
|
||||
_env(env), _sigh(), _buffer(buffer), _sessions(sessions), _element(this),
|
||||
_ram_ds()
|
||||
{
|
||||
_sessions.insert(this);
|
||||
_sessions.insert(&_element);
|
||||
}
|
||||
|
||||
~Session_component() { _sessions.remove(this); }
|
||||
~Session_component() { _sessions.remove(&_element); }
|
||||
|
||||
void notify_client()
|
||||
{
|
||||
@@ -136,11 +141,13 @@ class Remote_rom::Root : public Genode::Root_component<Session_component>
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
Session_component *_create_session(const char *)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* TODO compare requested module name with provided module name (config) */
|
||||
/*
|
||||
* TODO compare requested module name with provided module name (config)
|
||||
* */
|
||||
|
||||
return new (Root::md_alloc())
|
||||
Session_component(_env, _sessions, _buffer);
|
||||
@@ -149,17 +156,21 @@ class Remote_rom::Root : public Genode::Root_component<Session_component>
|
||||
public:
|
||||
|
||||
Root(Genode::Env &env, Genode::Allocator &md_alloc, Read_buffer &buffer)
|
||||
: Genode::Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc), _env(env), _buffer(buffer)
|
||||
:
|
||||
Genode::Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
|
||||
_env(env),
|
||||
_buffer(buffer),
|
||||
_sessions()
|
||||
{ }
|
||||
|
||||
void notify_clients()
|
||||
{
|
||||
for (Session_component *s = _sessions.first(); s; s = s->next())
|
||||
s->notify_client();
|
||||
for (Session_element *s = _sessions.first(); s; s = s->next())
|
||||
s->object()->notify_client();
|
||||
}
|
||||
};
|
||||
|
||||
struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom_receiver_base
|
||||
struct Remote_rom::Main : public Read_buffer, public Rom_receiver_base
|
||||
{
|
||||
Genode::Env &env;
|
||||
Genode::Heap heap = { &env.ram(), &env.rm() };
|
||||
@@ -174,7 +185,9 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom
|
||||
|
||||
char remotename[255];
|
||||
|
||||
Main(Genode::Env &env) : env(env), _ds_content_size(1024), _backend(backend_init_client(env, heap))
|
||||
Main(Genode::Env &env) :
|
||||
env(env), _ds(), _ds_content_size(1024),
|
||||
_backend(backend_init_client(env, heap))
|
||||
{
|
||||
try {
|
||||
Genode::Xml_node remote_rom = _config.xml().sub_node("remote_rom");
|
||||
@@ -223,7 +236,9 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom
|
||||
else {
|
||||
/* transfer default content if set */
|
||||
try {
|
||||
Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default");
|
||||
Genode::Xml_node default_content = _config.xml().
|
||||
sub_node("remote_rom").
|
||||
sub_node("default");
|
||||
return default_content.content_size();
|
||||
} catch (...) { }
|
||||
}
|
||||
@@ -241,8 +256,11 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom
|
||||
else {
|
||||
/* transfer default content if set */
|
||||
try {
|
||||
Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default");
|
||||
size_t const len = Genode::min(dst_len, default_content.content_size());
|
||||
Genode::Xml_node default_content = _config.xml().
|
||||
sub_node("remote_rom").
|
||||
sub_node("default");
|
||||
size_t const len = Genode::min(dst_len,
|
||||
default_content.content_size());
|
||||
Genode::memcpy(dst, default_content.content_base(), len);
|
||||
return len;
|
||||
} catch (...) { }
|
||||
@@ -252,10 +270,9 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom
|
||||
};
|
||||
|
||||
namespace Component {
|
||||
Genode::size_t stack_size() { return 2*1024*sizeof(long); }
|
||||
Genode::size_t stack_size() { return 2*1024*sizeof(long); }
|
||||
void construct(Genode::Env &env)
|
||||
{
|
||||
env.exec_static_constructors();
|
||||
static Remote_rom::Main main(env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* \date 2016-02-15
|
||||
*
|
||||
* Usage scenario:
|
||||
* __________ ________________ _________________ __________
|
||||
* | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client |
|
||||
* | | | server | | client | | |
|
||||
* ---------- ---------------- ----------------- ----------
|
||||
* __________ ______________ ______________ __________
|
||||
* | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client |
|
||||
* | | | server | | client | | |
|
||||
* ---------- -------------- -------------- ----------
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -46,7 +46,8 @@ struct Remote_rom::Rom_forwarder : Rom_forwarder_base
|
||||
|
||||
Attached_rom_dataspace &_config;
|
||||
|
||||
Rom_forwarder(Attached_rom_dataspace &rom, Backend_server_base &backend, Attached_rom_dataspace &config)
|
||||
Rom_forwarder(Attached_rom_dataspace &rom, Backend_server_base &backend,
|
||||
Attached_rom_dataspace &config)
|
||||
: _rom(rom), _backend(backend), _config(config)
|
||||
{
|
||||
_backend.register_forwarder(this);
|
||||
@@ -74,11 +75,14 @@ struct Remote_rom::Rom_forwarder : Rom_forwarder_base
|
||||
if (binary)
|
||||
return _rom.size();
|
||||
else
|
||||
return Genode::min(1+Genode::strlen(_rom.local_addr<char>()), _rom.size());
|
||||
return Genode::min(1+Genode::strlen(_rom.local_addr<char>()),
|
||||
_rom.size());
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default");
|
||||
Genode::Xml_node default_content = _config.xml().
|
||||
sub_node("remote_rom").
|
||||
sub_node("default");
|
||||
return default_content.content_size();
|
||||
} catch (...) { }
|
||||
}
|
||||
@@ -95,8 +99,11 @@ struct Remote_rom::Rom_forwarder : Rom_forwarder_base
|
||||
else {
|
||||
/* transfer default content if set */
|
||||
try {
|
||||
Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default");
|
||||
size_t const len = Genode::min(dst_len, default_content.content_size()-offset);
|
||||
Genode::Xml_node default_content = _config.xml().
|
||||
sub_node("remote_rom").
|
||||
sub_node("default");
|
||||
size_t const remainder = default_content.content_size()-offset;
|
||||
size_t const len = Genode::min(dst_len, remainder);
|
||||
Genode::memcpy(dst, default_content.content_base() + offset, len);
|
||||
return len;
|
||||
} catch (...) { }
|
||||
@@ -115,7 +122,8 @@ struct Remote_rom::Main
|
||||
Attached_rom_dataspace _rom;
|
||||
Rom_forwarder _forwarder;
|
||||
|
||||
Genode::Signal_handler<Rom_forwarder> _dispatcher = { _env.ep(), _forwarder, &Rom_forwarder::update };
|
||||
Genode::Signal_handler<Rom_forwarder> _dispatcher = {_env.ep(), _forwarder,
|
||||
&Rom_forwarder::update};
|
||||
|
||||
Main(Genode::Env &env)
|
||||
: _env(env),
|
||||
@@ -133,17 +141,19 @@ namespace Component {
|
||||
|
||||
void construct(Genode::Env &env)
|
||||
{
|
||||
env.exec_static_constructors();
|
||||
using Remote_rom::modulename;
|
||||
using Remote_rom::remotename;
|
||||
|
||||
Genode::Attached_rom_dataspace config = { env, "config" };
|
||||
try {
|
||||
Genode::Xml_node remote_rom = config.xml().sub_node("remote_rom");
|
||||
if (remote_rom.has_attribute("localname"))
|
||||
remote_rom.attribute("localname").value(Remote_rom::modulename, sizeof(Remote_rom::modulename));
|
||||
remote_rom.attribute("localname").value(modulename,
|
||||
sizeof(modulename));
|
||||
else
|
||||
remote_rom.attribute("name").value(Remote_rom::modulename, sizeof(Remote_rom::modulename));
|
||||
remote_rom.attribute("name").value(modulename, sizeof(modulename));
|
||||
|
||||
remote_rom.attribute("name").value(Remote_rom::remotename, sizeof(Remote_rom::remotename));
|
||||
remote_rom.attribute("name").value(remotename, sizeof(remotename));
|
||||
try {
|
||||
remote_rom.attribute("binary").value(&Remote_rom::binary);
|
||||
} catch (...) { }
|
||||
|
||||
Reference in New Issue
Block a user