mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
ealanos: Rewrote Kuori remote shell component to use Hoitaja's new Shell service. This removes the limitations of the Launcher session that only allowed start nodes to be 640 characters long.
This commit is contained in:
@@ -1,352 +1,216 @@
|
||||
#include <base/heap.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <libc/component.h>
|
||||
#include "base/attached_ram_dataspace.h"
|
||||
#include "base/ram_allocator.h"
|
||||
#include "region_map/region_map.h"
|
||||
#include "sys/_pthreadtypes.h"
|
||||
#include "util/xml_node.h"
|
||||
#include <base/log.h>
|
||||
#include <lwip/lwip_genode_init.h>
|
||||
#include <lwip/nic_netif.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <ealanos/laucher/connection.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <cstring>
|
||||
#include <libc/component.h>
|
||||
#include <internal/thread_create.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Lwip {
|
||||
extern "C" {
|
||||
#include <lwip/arch.h>
|
||||
#include <lwip/opt.h>
|
||||
#include <lwip/tcp.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <ealanos/shell/connection.h>
|
||||
|
||||
#include "protocol.h"
|
||||
namespace Ealan {
|
||||
namespace Kuori {
|
||||
class Server;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ealan::Kuori {
|
||||
using namespace Genode;
|
||||
class Main;
|
||||
}
|
||||
|
||||
class Ealan::Kuori::Main
|
||||
static void print(Genode::Output &output, sockaddr_in const &addr)
|
||||
{
|
||||
private:
|
||||
Heap &_heap;
|
||||
Genode::print(output, (ntohl(addr.sin_addr.s_addr) >> 24) & 0xff);
|
||||
output.out_string(".");
|
||||
Genode::print(output, (ntohl(addr.sin_addr.s_addr) >> 16) & 0xff);
|
||||
output.out_string(".");
|
||||
Genode::print(output, (ntohl(addr.sin_addr.s_addr) >> 8) & 0xff);
|
||||
output.out_string(".");
|
||||
Genode::print(output, (ntohl(addr.sin_addr.s_addr) >> 0) & 0xff);
|
||||
output.out_string(":");
|
||||
Genode::print(output, ntohs(addr.sin_port));
|
||||
}
|
||||
class Ealan::Kuori::Server
|
||||
{
|
||||
private:
|
||||
|
||||
Ealan::Launcher_connection &_hoitaja;
|
||||
Libc::Env &_env;
|
||||
Genode::Attached_rom_dataspace _config_rom {_env, "config"};
|
||||
Genode::Xml_node _config{_config_rom.xml()};
|
||||
Ealan::Shell::Connection _shell{_env};
|
||||
|
||||
struct Wakeup_scheduler : Lwip::Nic_netif::Wakeup_scheduler
|
||||
{
|
||||
Lwip::Nic_netif *nic{nullptr};
|
||||
void _die(const char *reason){ perror(reason); _env.parent().exit(1); }
|
||||
|
||||
void schedule_nic_server_wakeup() override
|
||||
{
|
||||
nic->wakeup_nic_server();
|
||||
}
|
||||
struct handler {
|
||||
pthread_t *thread;
|
||||
Server *server;
|
||||
int cd;
|
||||
};
|
||||
|
||||
void set_nic(Lwip::Nic_netif *nic)
|
||||
{
|
||||
this->nic = nic;
|
||||
}
|
||||
char *_config_ptr;
|
||||
|
||||
Wakeup_scheduler() = default;
|
||||
} _wakeup_scheduler;
|
||||
public:
|
||||
|
||||
enum states
|
||||
{
|
||||
NONE = 0,
|
||||
ACCEPTED,
|
||||
RECEIVED,
|
||||
CLOSING
|
||||
};
|
||||
using Command = Ealan::Kuori::Package_header::Command;
|
||||
using Header = Ealan::Kuori::Package_header;
|
||||
using State = Ealan::Kuori::Package_header::State;
|
||||
|
||||
struct state
|
||||
{
|
||||
uint8_t state;
|
||||
uint8_t retries;
|
||||
struct Lwip::tcp_pcb *pcb;
|
||||
struct Lwip::pbuf *p;
|
||||
};
|
||||
|
||||
Lwip::tcp_pcb *listen_socket;
|
||||
uint16_t _port{8080};
|
||||
|
||||
Server(Libc::Env &env) : _env(env) {}
|
||||
|
||||
struct Tcp_connection
|
||||
{
|
||||
static Main *kuori;
|
||||
/**
|
||||
* @brief Free state and lwip objects
|
||||
*
|
||||
* @param s
|
||||
*/
|
||||
static void free(struct state *s)
|
||||
{
|
||||
if (s != nullptr) {
|
||||
if (s->p) {
|
||||
Lwip::pbuf_free(s->p);
|
||||
}
|
||||
Lwip::mem_free(s);
|
||||
}
|
||||
}
|
||||
static void *handle(void *args)
|
||||
{
|
||||
struct handler *h = reinterpret_cast<struct handler *>(args);
|
||||
h->server->handle_connection(h->cd);
|
||||
delete h->thread;
|
||||
delete h;
|
||||
|
||||
static void close(struct Lwip::tcp_pcb *tpcb, struct state *s)
|
||||
{
|
||||
Lwip::tcp_arg(tpcb, nullptr);
|
||||
Lwip::tcp_sent(tpcb, nullptr);
|
||||
Lwip::tcp_recv(tpcb, nullptr);
|
||||
Lwip::tcp_err(tpcb, nullptr);
|
||||
Lwip::tcp_poll(tpcb, nullptr, 0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
free(s);
|
||||
Lwip::tcp_close(tpcb);
|
||||
}
|
||||
void handle_connection(int cd)
|
||||
{
|
||||
Header header;
|
||||
|
||||
while (true) {
|
||||
int ret = read(cd, &header, sizeof(header));
|
||||
|
||||
static void send(struct Lwip::tcp_pcb *tpcb, struct state *s)
|
||||
{
|
||||
struct Lwip::pbuf *ptr;
|
||||
Lwip::err_t wr_err = Lwip::ERR_OK;
|
||||
if (!ret) break;
|
||||
|
||||
while ((wr_err == Lwip::ERR_OK) && (s->p != nullptr))
|
||||
{
|
||||
ptr = s->p;
|
||||
if (ret > 0) {
|
||||
Request request{header.command, header.length, cd};
|
||||
Genode::log("size of command: ", sizeof(Command));
|
||||
Genode::log("CMD=", static_cast<unsigned int>(request.command), " CD=", cd, " LEN=", header.length);
|
||||
process_request(request);
|
||||
}
|
||||
}
|
||||
|
||||
wr_err = Lwip::tcp_write(tpcb, ptr->payload, ptr->len, 3);
|
||||
if (wr_err == Lwip::ERR_OK) {
|
||||
uint16_t plen;
|
||||
}
|
||||
|
||||
plen = ptr->len;
|
||||
s->p = ptr->next;
|
||||
void process_request(Request &request)
|
||||
{
|
||||
switch (request.command) {
|
||||
case Command::BEGIN:
|
||||
{
|
||||
|
||||
/* Acknowledge the new transaction */
|
||||
|
||||
if (s->p) {
|
||||
Lwip::pbuf_ref(s->p);
|
||||
}
|
||||
Lwip::pbuf_free(ptr);
|
||||
Lwip::tcp_recved(tpcb, plen);
|
||||
} else if (wr_err == Lwip::ERR_MEM) {
|
||||
s->p = ptr;
|
||||
} else {
|
||||
Genode::error("Encountered LwIP error code ", static_cast<signed int>(wr_err));
|
||||
}
|
||||
}
|
||||
}
|
||||
Header *ack = new Header {Command::ACK, State::ACCEPT, static_cast<std::uint32_t>(::strlen(_config_ptr)) };
|
||||
write(request.cd, ack, sizeof(Header));
|
||||
|
||||
static void error(void *arg, Lwip::err_t error)
|
||||
{
|
||||
struct state *s;
|
||||
/* Send habitat configuration to client */
|
||||
write(request.cd, _config_ptr, ::strlen(_config_ptr));
|
||||
break;
|
||||
}
|
||||
|
||||
LWIP_UNUSED_ARG(error);
|
||||
case Command::COMMIT:
|
||||
{
|
||||
char *buf = new char[request.length];
|
||||
Genode::log("Commit: Awaiting ", request.length, " bytes");
|
||||
std::uint32_t bytes = 0;
|
||||
int rc = 0;
|
||||
|
||||
s = static_cast<struct state *>(arg);
|
||||
while (bytes < request.length) {
|
||||
rc = read(request.cd, &buf[bytes], request.length);
|
||||
if (rc == 0)
|
||||
break;
|
||||
Genode::log("Read ", rc, " bytes.");
|
||||
bytes += rc;
|
||||
}
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
static Lwip::err_t poll(void *arg, struct Lwip::tcp_pcb *tpcb)
|
||||
{
|
||||
Lwip::err_t rc;
|
||||
struct state *s;
|
||||
memcpy(_config_ptr, buf, request.length);
|
||||
_config_ptr[bytes] = '\0';
|
||||
|
||||
s = static_cast<struct state *>(arg);
|
||||
if (s) {
|
||||
if (s->p) {
|
||||
send(tpcb, s);
|
||||
} else {
|
||||
if (s->state == CLOSING) {
|
||||
close(tpcb, s);
|
||||
}
|
||||
}
|
||||
rc = Lwip::ERR_OK;
|
||||
} else {
|
||||
Lwip::tcp_abort(tpcb);
|
||||
rc = Lwip::ERR_ABRT;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
printf("Read new configuration:\n %s\n", _config_ptr);
|
||||
|
||||
static Lwip::err_t sent(void *arg, struct Lwip::tcp_pcb *tpcb, [[maybe_unused]] Lwip::u16_t len)
|
||||
{
|
||||
struct state *s;
|
||||
_shell.commit();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s = static_cast<struct state *>(arg);
|
||||
s->retries = 0;
|
||||
void run()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (s->p) {
|
||||
Lwip::tcp_sent(tpcb, sent);
|
||||
send(tpcb, s);
|
||||
} else {
|
||||
if (s->state == CLOSING) {
|
||||
close(tpcb, s);
|
||||
}
|
||||
}
|
||||
return Lwip::ERR_OK;
|
||||
}
|
||||
Genode::log("Kuori v1.0 - Remote Shell for EalánOS");
|
||||
|
||||
static Lwip::err_t receive(void *arg, struct Lwip::tcp_pcb *tpcb, struct Lwip::pbuf *p, Lwip::err_t err)
|
||||
{
|
||||
struct state *s;
|
||||
Lwip::err_t rc = Lwip::ERR_OK;
|
||||
Genode::Ram_dataspace_capability cap = _shell.connect();
|
||||
Genode::Region_map::Attr attr{};
|
||||
attr.writeable = true;
|
||||
|
||||
s = static_cast<struct state *>(arg);
|
||||
|
||||
if (!p) {
|
||||
s->state = CLOSING;
|
||||
if (!s->p) {
|
||||
close(tpcb, s);
|
||||
} else {
|
||||
send(tpcb, s);
|
||||
}
|
||||
rc = Lwip::ERR_OK;
|
||||
} else if (err != Lwip::ERR_OK) {
|
||||
rc = err;
|
||||
} else if (s->state == ACCEPTED) {
|
||||
s->state = RECEIVED;
|
||||
kuori->parse_and_launch(tpcb, p, s);
|
||||
}
|
||||
else if (s->state == RECEIVED)
|
||||
{
|
||||
if (!s->p) {
|
||||
s->p = p;
|
||||
kuori->parse_and_launch(tpcb, p, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct Lwip::pbuf *ptr;
|
||||
ptr = s->p;
|
||||
Lwip::pbuf_cat(ptr, p);
|
||||
}
|
||||
rc = Lwip::ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Lwip::tcp_recved(tpcb, p->tot_len);
|
||||
Lwip::pbuf_free(p);
|
||||
rc = Lwip::ERR_OK;
|
||||
}
|
||||
_config_ptr = _env.rm().attach(cap, attr).convert<char *>(
|
||||
[&](Genode::Region_map::Range r) { return reinterpret_cast<char*>(r.start); }, [&] (Genode::Region_map::Attach_error) { return nullptr; });
|
||||
|
||||
return rc;
|
||||
}
|
||||
if (!_config_ptr) _die("Failed mapping habitat config");
|
||||
|
||||
static Lwip::err_t accept([[maybe_unused]] void *arg, struct Lwip::tcp_pcb *newpcb, Lwip::err_t err)
|
||||
{
|
||||
Lwip::err_t rc;
|
||||
struct state *s;
|
||||
Genode::log("Mapped habitat configuration");
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
printf("%s\n", _config_ptr);
|
||||
|
||||
int const sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sd == -1) { _die("socket"); }
|
||||
|
||||
if ((err != Lwip::ERR_OK) || (newpcb == nullptr)) {
|
||||
return Lwip::ERR_VAL;
|
||||
}
|
||||
unsigned const port = _config.attribute_value("port", 8080U);
|
||||
|
||||
s = static_cast<struct state *>(Lwip::mem_malloc(sizeof(struct state)));
|
||||
if (s) {
|
||||
s->state = ACCEPTED;
|
||||
s->pcb = newpcb;
|
||||
s->retries = 0;
|
||||
s->p = nullptr;
|
||||
sockaddr_in const addr{0, AF_INET, htons(port), {INADDR_ANY}, {INADDR_ANY}};
|
||||
sockaddr const *paddr = reinterpret_cast<sockaddr const *>(&addr);
|
||||
|
||||
Lwip::tcp_arg(newpcb, s);
|
||||
Lwip::tcp_recv(newpcb, receive);
|
||||
Lwip::tcp_err(newpcb, error);
|
||||
Lwip::tcp_poll(newpcb, poll, 0);
|
||||
Lwip::tcp_sent(newpcb, sent);
|
||||
int const on = 1;
|
||||
rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
|
||||
rc = Lwip::ERR_OK;
|
||||
if (rc) _die("setsockopt");
|
||||
|
||||
Genode::log("Accepted new connection from ", const_cast<const char*>(Lwip::ipaddr_ntoa(&newpcb->remote_ip)));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = Lwip::ERR_MEM;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
rc = bind(sd, paddr, sizeof(addr));
|
||||
if (rc == -1) _die("bind");
|
||||
|
||||
};
|
||||
|
||||
void init()
|
||||
{
|
||||
listen_socket = Lwip::tcp_new_ip_type(Lwip::IPADDR_TYPE_ANY);
|
||||
rc = listen(sd, SOMAXCONN);
|
||||
if (rc == -1) _die("listen");
|
||||
|
||||
if (!listen_socket) {
|
||||
Genode::error("Failed to create server socket.");
|
||||
}
|
||||
Genode::log("Kuori service up and running.");
|
||||
|
||||
Lwip::err_t err;
|
||||
err = Lwip::tcp_bind(listen_socket, &Lwip::ip_addr_any, _port);
|
||||
|
||||
if (err == Lwip::ERR_OK) {
|
||||
listen_socket = Lwip::tcp_listen_with_backlog(listen_socket, 255);
|
||||
Lwip::tcp_accept(listen_socket, Tcp_connection::accept);
|
||||
} else {
|
||||
Genode::error("Failed to bind socket.");
|
||||
}
|
||||
while (true) {
|
||||
sockaddr_in caddr;
|
||||
socklen_t scaddr = sizeof(caddr);
|
||||
sockaddr *pcaddr = reinterpret_cast<sockaddr *>(&caddr);
|
||||
|
||||
Tcp_connection::kuori = this;
|
||||
int const cd = accept(sd, pcaddr, &scaddr);
|
||||
if (cd == -1) _die("accept");
|
||||
|
||||
Genode::log("Kuori v0.1 - Remote shell for EalánOS");
|
||||
}
|
||||
Genode::log("New connection from ", caddr);
|
||||
struct handler *handler = new struct handler();
|
||||
handler->cd = cd;
|
||||
handler->server = this;
|
||||
handler->thread = new pthread_t();
|
||||
|
||||
Lwip::Nic_netif _netif;
|
||||
|
||||
public:
|
||||
Main(Env &env, Genode::Heap &heap, Xml_node config, Ealan::Launcher_connection &hoitaja) : _heap(heap), _hoitaja(hoitaja), _wakeup_scheduler(), _netif(env, _heap, config, _wakeup_scheduler) {
|
||||
|
||||
_wakeup_scheduler.set_nic(&_netif);
|
||||
init();
|
||||
}
|
||||
|
||||
void parse_and_launch(Lwip::tcp_pcb *tpcb, Lwip::pbuf *p, state *state)
|
||||
{
|
||||
try {
|
||||
Genode::log("Parsing input of length ", p->len);
|
||||
Genode::log(static_cast<const char *>(p->payload));
|
||||
Xml_node start_node(static_cast<char *>(p->payload));
|
||||
//Genode::log(start_node);
|
||||
|
||||
Genode::String<90> name = start_node.attribute_value("name", Genode::String<90>());
|
||||
char msg[120];
|
||||
|
||||
std::sprintf(msg, "Lauching %s\n", name.string());
|
||||
|
||||
Genode::String<640> cell_cfg(static_cast<const char*>(p->payload));
|
||||
Genode::log(cell_cfg);
|
||||
_hoitaja.launch(cell_cfg);
|
||||
|
||||
Lwip::pbuf *response_buffer = Lwip::pbuf_alloc(Lwip::PBUF_TRANSPORT, static_cast<Lwip::u16_t>(Genode::strlen(msg)), Lwip::PBUF_RAM);
|
||||
|
||||
Lwip::pbuf_take(response_buffer, msg, static_cast<Lwip::u16_t>(Genode::strlen(msg)));
|
||||
|
||||
state->p = response_buffer;
|
||||
Tcp_connection::send(tpcb, state);
|
||||
}
|
||||
catch (Genode::Xml_attribute::Invalid_syntax)
|
||||
{
|
||||
Genode::error("Invalid config supplied.");
|
||||
Genode::String<100> response("Invalid cell configuration.\n");
|
||||
|
||||
Lwip::pbuf *response_buffer = Lwip::pbuf_alloc(Lwip::PBUF_TRANSPORT, static_cast<Lwip::u16_t>(response.length()), Lwip::PBUF_RAM);
|
||||
Lwip::pbuf_take(response_buffer, response.string(), static_cast<Lwip::u16_t>(response.length()));
|
||||
|
||||
state->p = response_buffer;
|
||||
Tcp_connection::send(tpcb, state);
|
||||
}
|
||||
}
|
||||
Genode::String<32> const name {"kuori#", caddr};
|
||||
|
||||
Libc::pthread_create_from_session(handler->thread, Server::handle, handler, 8*4096, name.string(), &_env.cpu(), _env.cpu().affinity_space().location_of_index(0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ealan::Kuori::Main *Ealan::Kuori::Main::Tcp_connection::kuori;
|
||||
|
||||
void Libc::Component::construct(Libc::Env &env)
|
||||
{
|
||||
Genode::Attached_rom_dataspace _config{env, "config"};
|
||||
Genode::Xml_node config = _config.xml();
|
||||
static Ealan::Kuori::Server kuori(env);
|
||||
|
||||
static Genode::Heap heap{env.ram(), env.rm()};
|
||||
|
||||
static Timer::Connection timer{env};
|
||||
|
||||
Lwip::genode_init(heap, timer);
|
||||
|
||||
Genode::Thread *myself = Genode::Thread::myself();
|
||||
Genode::Affinity::Location loc = myself->affinity();
|
||||
Genode::Affinity affinity(env.cpu().affinity_space(), loc);
|
||||
|
||||
static Ealan::Launcher_connection hoitaja{env, affinity};
|
||||
|
||||
static Ealan::Kuori::Main kuori(env, heap, config, hoitaja);
|
||||
}
|
||||
Libc::with_libc([&]() {
|
||||
kuori.run();
|
||||
});
|
||||
}
|
||||
|
||||
36
repos/ealanos/src/app/kuori/protocol.h
Normal file
36
repos/ealanos/src/app/kuori/protocol.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef __EALANOS__SRC__APP__KUORI__PROTOCOL_H_
|
||||
#define __EALANOS__SRC__APP__KUORI__PROTOCOL_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Ealan
|
||||
{
|
||||
namespace Kuori
|
||||
{
|
||||
using Handle = std::uint16_t;
|
||||
|
||||
struct Package_header {
|
||||
enum Command { BEGIN, COMMIT, ACK };
|
||||
|
||||
enum State {
|
||||
ACCEPT,
|
||||
FAILED,
|
||||
SUCCESS,
|
||||
WAIT
|
||||
};
|
||||
|
||||
Command command;
|
||||
State state;
|
||||
std::uint32_t length;
|
||||
};
|
||||
|
||||
struct Request {
|
||||
Package_header::Command command;
|
||||
std::uint32_t length;
|
||||
int cd;
|
||||
};
|
||||
}
|
||||
// namespace Kuori
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,22 +1,8 @@
|
||||
SRC_CC = main.cc
|
||||
SRC_CC += vfs.cc printf.cc rand.cc sys_arch.cc
|
||||
TARGET = kuori
|
||||
|
||||
LIBPORTS_DIR = $(REP_DIR)/../libports
|
||||
VFS_DIR = $(LIBPORTS_DIR)/src/lib/vfs/lwip
|
||||
vpath %.cc $(VFS_DIR)
|
||||
|
||||
|
||||
LWIP_PORT_DIR := $(call select_from_ports,lwip)
|
||||
LWIPDIR := $(LWIP_PORT_DIR)/src/lib/lwip/src
|
||||
INC_DIR += $(LWIP_PORT_DIR)/include/lwip \
|
||||
$(LWIPDIR)/include \
|
||||
$(LWIPDIR)/include/ipv4 \
|
||||
$(LWIPDIR)/include/api \
|
||||
$(LWIPDIR)/include/netif \
|
||||
$(LIBPORTS_DIR)/src/lib/lwip/include \
|
||||
$(LIBPORTS_DIR)/src/lib/vfs \
|
||||
$(LIBPORTS_DIR)/src/lib/vfs/lwip
|
||||
INC_DIR += $(call select_from_repositories,src/lib/libc)
|
||||
INC_DIR += $(call select_from_repositories,src/lib/libc)/spec/x86_64
|
||||
|
||||
CC_OPT += -Wno-error=conversion -Wno-error=effc++
|
||||
LIBS += base libm libc lwip stdcxx
|
||||
Reference in New Issue
Block a user