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
|
||||
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/_:
|
||||
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
|
||||
|
||||
@@ -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