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;
|
||||
static void print(Genode::Output &output, sockaddr_in const &addr)
|
||||
{
|
||||
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::Main
|
||||
class Ealan::Kuori::Server
|
||||
{
|
||||
private:
|
||||
Heap &_heap;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void set_nic(Lwip::Nic_netif *nic)
|
||||
{
|
||||
this->nic = nic;
|
||||
}
|
||||
|
||||
Wakeup_scheduler() = default;
|
||||
} _wakeup_scheduler;
|
||||
|
||||
enum states
|
||||
{
|
||||
NONE = 0,
|
||||
ACCEPTED,
|
||||
RECEIVED,
|
||||
CLOSING
|
||||
struct handler {
|
||||
pthread_t *thread;
|
||||
Server *server;
|
||||
int cd;
|
||||
};
|
||||
|
||||
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};
|
||||
|
||||
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 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);
|
||||
|
||||
free(s);
|
||||
Lwip::tcp_close(tpcb);
|
||||
}
|
||||
|
||||
static void send(struct Lwip::tcp_pcb *tpcb, struct state *s)
|
||||
{
|
||||
struct Lwip::pbuf *ptr;
|
||||
Lwip::err_t wr_err = Lwip::ERR_OK;
|
||||
|
||||
while ((wr_err == Lwip::ERR_OK) && (s->p != nullptr))
|
||||
{
|
||||
ptr = s->p;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void error(void *arg, Lwip::err_t error)
|
||||
{
|
||||
struct state *s;
|
||||
|
||||
LWIP_UNUSED_ARG(error);
|
||||
|
||||
s = static_cast<struct state *>(arg);
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
static Lwip::err_t poll(void *arg, struct Lwip::tcp_pcb *tpcb)
|
||||
{
|
||||
Lwip::err_t rc;
|
||||
struct state *s;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static Lwip::err_t sent(void *arg, struct Lwip::tcp_pcb *tpcb, [[maybe_unused]] Lwip::u16_t len)
|
||||
{
|
||||
struct state *s;
|
||||
|
||||
s = static_cast<struct state *>(arg);
|
||||
s->retries = 0;
|
||||
|
||||
if (s->p) {
|
||||
Lwip::tcp_sent(tpcb, sent);
|
||||
send(tpcb, s);
|
||||
} else {
|
||||
if (s->state == CLOSING) {
|
||||
close(tpcb, s);
|
||||
}
|
||||
}
|
||||
return Lwip::ERR_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
|
||||
if ((err != Lwip::ERR_OK) || (newpcb == nullptr)) {
|
||||
return Lwip::ERR_VAL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
rc = Lwip::ERR_OK;
|
||||
|
||||
Genode::log("Accepted new connection from ", const_cast<const char*>(Lwip::ipaddr_ntoa(&newpcb->remote_ip)));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = Lwip::ERR_MEM;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void init()
|
||||
{
|
||||
listen_socket = Lwip::tcp_new_ip_type(Lwip::IPADDR_TYPE_ANY);
|
||||
|
||||
if (!listen_socket) {
|
||||
Genode::error("Failed to create server socket.");
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
Tcp_connection::kuori = this;
|
||||
|
||||
Genode::log("Kuori v0.1 - Remote shell for EalánOS");
|
||||
}
|
||||
|
||||
Lwip::Nic_netif _netif;
|
||||
char *_config_ptr;
|
||||
|
||||
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();
|
||||
using Command = Ealan::Kuori::Package_header::Command;
|
||||
using Header = Ealan::Kuori::Package_header;
|
||||
using State = Ealan::Kuori::Package_header::State;
|
||||
|
||||
|
||||
Server(Libc::Env &env) : _env(env) {}
|
||||
|
||||
static void *handle(void *args)
|
||||
{
|
||||
struct handler *h = reinterpret_cast<struct handler *>(args);
|
||||
h->server->handle_connection(h->cd);
|
||||
delete h->thread;
|
||||
delete h;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void parse_and_launch(Lwip::tcp_pcb *tpcb, Lwip::pbuf *p, state *state)
|
||||
void handle_connection(int cd)
|
||||
{
|
||||
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);
|
||||
Header header;
|
||||
|
||||
Genode::String<90> name = start_node.attribute_value("name", Genode::String<90>());
|
||||
char msg[120];
|
||||
while (true) {
|
||||
int ret = read(cd, &header, sizeof(header));
|
||||
|
||||
std::sprintf(msg, "Lauching %s\n", name.string());
|
||||
if (!ret) break;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
catch (Genode::Xml_attribute::Invalid_syntax)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void process_request(Request &request)
|
||||
{
|
||||
switch (request.command) {
|
||||
case Command::BEGIN:
|
||||
{
|
||||
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()));
|
||||
/* Acknowledge the new transaction */
|
||||
|
||||
state->p = response_buffer;
|
||||
Tcp_connection::send(tpcb, state);
|
||||
Header *ack = new Header {Command::ACK, State::ACCEPT, static_cast<std::uint32_t>(::strlen(_config_ptr)) };
|
||||
write(request.cd, ack, sizeof(Header));
|
||||
|
||||
/* Send habitat configuration to client */
|
||||
write(request.cd, _config_ptr, ::strlen(_config_ptr));
|
||||
break;
|
||||
}
|
||||
|
||||
case Command::COMMIT:
|
||||
{
|
||||
char *buf = new char[request.length];
|
||||
Genode::log("Commit: Awaiting ", request.length, " bytes");
|
||||
std::uint32_t bytes = 0;
|
||||
int rc = 0;
|
||||
|
||||
while (bytes < request.length) {
|
||||
rc = read(request.cd, &buf[bytes], request.length);
|
||||
if (rc == 0)
|
||||
break;
|
||||
Genode::log("Read ", rc, " bytes.");
|
||||
bytes += rc;
|
||||
}
|
||||
|
||||
|
||||
memcpy(_config_ptr, buf, request.length);
|
||||
_config_ptr[bytes] = '\0';
|
||||
|
||||
printf("Read new configuration:\n %s\n", _config_ptr);
|
||||
|
||||
_shell.commit();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
Genode::log("Kuori v1.0 - Remote Shell for EalánOS");
|
||||
|
||||
Genode::Ram_dataspace_capability cap = _shell.connect();
|
||||
Genode::Region_map::Attr attr{};
|
||||
attr.writeable = true;
|
||||
|
||||
_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; });
|
||||
|
||||
if (!_config_ptr) _die("Failed mapping habitat config");
|
||||
|
||||
Genode::log("Mapped habitat configuration");
|
||||
|
||||
printf("%s\n", _config_ptr);
|
||||
|
||||
int const sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sd == -1) { _die("socket"); }
|
||||
|
||||
unsigned const port = _config.attribute_value("port", 8080U);
|
||||
|
||||
sockaddr_in const addr{0, AF_INET, htons(port), {INADDR_ANY}, {INADDR_ANY}};
|
||||
sockaddr const *paddr = reinterpret_cast<sockaddr const *>(&addr);
|
||||
|
||||
int const on = 1;
|
||||
rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
|
||||
if (rc) _die("setsockopt");
|
||||
|
||||
rc = bind(sd, paddr, sizeof(addr));
|
||||
if (rc == -1) _die("bind");
|
||||
|
||||
rc = listen(sd, SOMAXCONN);
|
||||
if (rc == -1) _die("listen");
|
||||
|
||||
Genode::log("Kuori service up and running.");
|
||||
|
||||
while (true) {
|
||||
sockaddr_in caddr;
|
||||
socklen_t scaddr = sizeof(caddr);
|
||||
sockaddr *pcaddr = reinterpret_cast<sockaddr *>(&caddr);
|
||||
|
||||
int const cd = accept(sd, pcaddr, &scaddr);
|
||||
if (cd == -1) _die("accept");
|
||||
|
||||
Genode::log("New connection from ", caddr);
|
||||
struct handler *handler = new struct handler();
|
||||
handler->cd = cd;
|
||||
handler->server = this;
|
||||
handler->thread = new pthread_t();
|
||||
|
||||
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