mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
@@ -395,10 +395,6 @@ Separate components
|
|||||||
The terminal crosslink service allows to terminal clients to talk to each
|
The terminal crosslink service allows to terminal clients to talk to each
|
||||||
other.
|
other.
|
||||||
|
|
||||||
:_gems/src/server/http_block/_:
|
|
||||||
A block service that fetches a virtual block device over the network from
|
|
||||||
a HTTP server.
|
|
||||||
|
|
||||||
:_os/src/server/fs_rom/_:
|
:_os/src/server/fs_rom/_:
|
||||||
A ROM service that translates the 'File_system' session interface to the
|
A ROM service that translates the 'File_system' session interface to the
|
||||||
'ROM' session' interface. Each request for a ROM file is handled by looking
|
'ROM' session' interface. Each request for a ROM file is handled by looking
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
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_block">
|
|
||||||
! <resource name="RAM" quantum="1M" />
|
|
||||||
! <provides><service name="Block"/></provides> <!-- Mandatory -->
|
|
||||||
! <config uri="http://kc86.genode.labs:80/file.iso" block_size=2048/>
|
|
||||||
!</start>
|
|
||||||
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief HTTP protocol parts
|
|
||||||
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
|
|
||||||
* \date 2010-08-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2010-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base/child.h>
|
|
||||||
#include <base/log.h>
|
|
||||||
#include <base/sleep.h>
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "http.h"
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
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 (write(_fd, _http_buf, length) != length) {
|
|
||||||
error("cmd_head: write error");
|
|
||||||
throw Http::Socket_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Http::connect()
|
|
||||||
{
|
|
||||||
_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (_fd < 0) {
|
|
||||||
error("connect: no socket avaiable");
|
|
||||||
throw Http::Socket_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (::connect(_fd, _info->ai_addr, sizeof(*(_info->ai_addr))) < 0) {
|
|
||||||
error("connect: connect failed");
|
|
||||||
throw Http::Socket_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Http::reconnect(){ close(_fd); connect(); }
|
|
||||||
|
|
||||||
|
|
||||||
void Http::resolve_uri()
|
|
||||||
{
|
|
||||||
struct addrinfo *info;
|
|
||||||
if (getaddrinfo(_host, _port, 0, &info)) {
|
|
||||||
error("host ", Cstring(_host), " not found");
|
|
||||||
throw Http::Uri_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
_heap.try_alloc(sizeof(struct addrinfo)).with_result(
|
|
||||||
|
|
||||||
[&] (void *ptr) {
|
|
||||||
_info = (struct addrinfo *)ptr;
|
|
||||||
Genode::memcpy(_info, info, sizeof(struct addrinfo));
|
|
||||||
},
|
|
||||||
|
|
||||||
[&] (Allocator::Alloc_error) {
|
|
||||||
throw Http::Uri_error();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Genode::size_t Http::read_header()
|
|
||||||
{
|
|
||||||
bool header = true; size_t i = 0;
|
|
||||||
|
|
||||||
while (header) {
|
|
||||||
if (!read(_fd, &_http_buf[i], 1))
|
|
||||||
throw Http::Socket_closed();
|
|
||||||
|
|
||||||
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) {
|
|
||||||
error("read_header: 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);
|
|
||||||
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 = read(_fd, (void *)((addr_t)buf + buf_fill),
|
|
||||||
size - buf_fill)) <= 0) {
|
|
||||||
error("could not read data (", errno, ")");
|
|
||||||
throw Http::Socket_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
buf_fill += part;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Http::Http(Genode::Heap &heap, ::String const &uri)
|
|
||||||
: _heap(heap), _port((char *)"80")
|
|
||||||
{
|
|
||||||
_heap.try_alloc(HTTP_BUF).with_result(
|
|
||||||
[&] (void *ptr) { _http_buf = (char *)ptr; },
|
|
||||||
[&] (Allocator::Alloc_error) { });
|
|
||||||
|
|
||||||
/* parse URI */
|
|
||||||
parse_uri(uri);
|
|
||||||
|
|
||||||
/* search for host */
|
|
||||||
resolve_uri();
|
|
||||||
|
|
||||||
/* connect to host */
|
|
||||||
connect();
|
|
||||||
|
|
||||||
/* retrieve file info */
|
|
||||||
get_capacity();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Http::~Http()
|
|
||||||
{
|
|
||||||
_heap.free(_host, Genode::strlen(_host) + 1);
|
|
||||||
_heap.free(_path, Genode::strlen(_path) + 2);
|
|
||||||
_heap.free(_http_buf, HTTP_BUF);
|
|
||||||
_heap.free(_info, sizeof(struct addrinfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Http::parse_uri(::String const &u)
|
|
||||||
{
|
|
||||||
/* strip possible http prefix */
|
|
||||||
const char *http = "http://";
|
|
||||||
char * uri = const_cast<char*>(u.string());
|
|
||||||
size_t length = Genode::strlen(uri);
|
|
||||||
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++) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* \param len number of cstring bytes w/o null-termination
|
|
||||||
*/
|
|
||||||
auto copied_cstring = [&] (char const *src, size_t len) -> char *
|
|
||||||
{
|
|
||||||
size_t const bytes = len + 1;
|
|
||||||
|
|
||||||
return _heap.try_alloc(bytes).convert<char *>(
|
|
||||||
|
|
||||||
[&] (void *ptr) {
|
|
||||||
char *dst = (char *)ptr;
|
|
||||||
copy_cstring(dst, src, bytes);
|
|
||||||
return dst; },
|
|
||||||
|
|
||||||
[&] (Allocator::Alloc_error) -> char * {
|
|
||||||
return nullptr; });
|
|
||||||
};
|
|
||||||
|
|
||||||
_host = copied_cstring(uri, i);
|
|
||||||
_path = copied_cstring(uri + i, length - i);
|
|
||||||
|
|
||||||
if (!_host || !_path) {
|
|
||||||
error("allocation failure during Http::parse_uri");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Http::cmd_get(size_t file_offset, size_t size, addr_t buffer)
|
|
||||||
{
|
|
||||||
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 (write(_fd, _http_buf, length) < 0) {
|
|
||||||
|
|
||||||
if (errno == ESHUTDOWN)
|
|
||||||
reconnect();
|
|
||||||
|
|
||||||
if (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) {
|
|
||||||
error("cmd_get: server returned ", _http_ret);
|
|
||||||
throw Http::Server_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_read((void *)(buffer), size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief HTTP back-end interface
|
|
||||||
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
|
|
||||||
* \date 2010-08-24
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2010-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HTTP_H_
|
|
||||||
#define _HTTP_H_
|
|
||||||
|
|
||||||
#include <base/stdint.h>
|
|
||||||
|
|
||||||
struct addrinfo;
|
|
||||||
|
|
||||||
using String = Genode::String<64>;
|
|
||||||
class Http
|
|
||||||
{
|
|
||||||
typedef Genode::size_t size_t;
|
|
||||||
typedef Genode::addr_t addr_t;
|
|
||||||
typedef Genode::off_t off_t;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Heap &_heap;
|
|
||||||
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(::String const &uri);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 host port is 80
|
|
||||||
*/
|
|
||||||
Http(Genode::Heap &heap, ::String const &uri);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
~Http();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read remote file size
|
|
||||||
*
|
|
||||||
* \return Remote file size in bytes
|
|
||||||
*/
|
|
||||||
size_t file_size() const { 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 buffer address in I/O dataspace
|
|
||||||
*/
|
|
||||||
void cmd_get(size_t file_offset, size_t size, addr_t buffer);
|
|
||||||
|
|
||||||
/* 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_ */
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Block interface for HTTP block driver
|
|
||||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
|
||||||
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
|
|
||||||
* \date 2010-08-24
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2010-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/attached_rom_dataspace.h>
|
|
||||||
#include <base/log.h>
|
|
||||||
#include <block/component.h>
|
|
||||||
#include <libc/component.h>
|
|
||||||
|
|
||||||
/* local includes */
|
|
||||||
#include "http.h"
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
class Driver : public Block::Driver
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
size_t _block_size;
|
|
||||||
Http _http;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Driver(Heap &heap, Ram_allocator &ram,
|
|
||||||
size_t block_size, ::String const &uri)
|
|
||||||
: Block::Driver(ram),
|
|
||||||
_block_size(block_size), _http(heap, uri) {}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************
|
|
||||||
** Block::Driver interface **
|
|
||||||
*******************************/
|
|
||||||
|
|
||||||
Block::Session::Info info() const override
|
|
||||||
{
|
|
||||||
return { .block_size = _block_size,
|
|
||||||
.block_count = _http.file_size() / _block_size,
|
|
||||||
.align_log2 = log2(_block_size),
|
|
||||||
.writeable = false };
|
|
||||||
}
|
|
||||||
|
|
||||||
void read(Block::sector_t block_nr,
|
|
||||||
Genode::size_t block_count,
|
|
||||||
char *buffer,
|
|
||||||
Block::Packet_descriptor &packet)
|
|
||||||
{
|
|
||||||
_http.cmd_get(block_nr * _block_size, block_count * _block_size,
|
|
||||||
(addr_t)buffer);
|
|
||||||
ack_packet(packet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Factory : public Block::Driver_factory
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Env &_env;
|
|
||||||
Heap &_heap;
|
|
||||||
Attached_rom_dataspace _config { _env, "config" };
|
|
||||||
::String const _uri;
|
|
||||||
size_t const _blk_sz;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Factory(Env &env, Heap &heap)
|
|
||||||
:
|
|
||||||
_env(env), _heap(heap),
|
|
||||||
_uri (_config.xml().attribute_value("uri", ::String())),
|
|
||||||
_blk_sz(_config.xml().attribute_value("block_size", 512U))
|
|
||||||
{
|
|
||||||
log("Using file=", _uri, " as device with block size ",
|
|
||||||
Hex(_blk_sz, Hex::OMIT_PREFIX), ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
Block::Driver *create() {
|
|
||||||
return new (&_heap) Driver(_heap, _env.ram(), _blk_sz, _uri); }
|
|
||||||
|
|
||||||
void destroy(Block::Driver *driver) {
|
|
||||||
Genode::destroy(&_heap, driver); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Main
|
|
||||||
{
|
|
||||||
Env &env;
|
|
||||||
Heap heap { env.ram(), env.rm() };
|
|
||||||
Factory factory { env, heap };
|
|
||||||
Block::Root root { env.ep(), heap, env.rm(), factory, true };
|
|
||||||
|
|
||||||
Main(Env &env) : env(env) {
|
|
||||||
env.parent().announce(env.ep().manage(root)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void Libc::Component::construct(Libc::Env &env) { static Main m(env); }
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
TARGET = http_block
|
|
||||||
SRC_CC = main.cc http.cc
|
|
||||||
LIBS = libc
|
|
||||||
|
|
||||||
CC_CXX_WARN_STRICT =
|
|
||||||
Reference in New Issue
Block a user