lwip: enhance http_srv_static and http_clnt

Both, client and server now read their IP config from their Genode config.
Furthermore, the client now waits 4 instead of 2 seconds before sending the
first request to prevent connection fails in tests with a slow startup. The
client truncates its packet dump for better readability.

Ref #114
This commit is contained in:
Martin Stein 2016-08-15 11:56:29 +02:00 committed by Christian Helmuth
parent 6a40c5c13d
commit dbbda9839b
5 changed files with 167 additions and 37 deletions

View File

@ -68,7 +68,10 @@ append config {
<any-service> <parent/> <any-child/> </any-service>
</route>
<config>
<libc stdout="/dev/log" stderr="/dev/log">
<libc stdout="/dev/log" stderr="/dev/log"
ip_addr="10.0.2.55" netmask="255.255.255.0"
gateway="10.0.2.1" http_port="80"
>
<vfs> <dir name="dev"> <log/> </dir> </vfs>
</libc>
</config>
@ -80,7 +83,10 @@ append config {
<any-service> <parent/> <any-child/> </any-service>
</route>
<config>
<libc stdout="/dev/log" stderr="/dev/log">
<libc
stdout="/dev/log" stderr="/dev/log" server_ip="10.0.2.55"
http_port="80"
>
<vfs> <dir name="dev"> <log/> </dir> </vfs>
</libc>
</config>
@ -108,7 +114,6 @@ set boot_modules {
# platform-specific modules
lappend_if [have_spec linux] boot_modules fb_sdl
lappend_if [have_spec ps2] boot_modules ps2_drv
append_platform_drv_boot_modules

View File

@ -62,7 +62,7 @@ append config {
</route>
</start>
<start name="lighttpd">
<resource name="RAM" quantum="256M" />
<resource name="RAM" quantum="128M" />
<config>
<arg value="lighttpd" />
<arg value="-f" />
@ -121,7 +121,10 @@ mimetype.assign = (
<any-service> <parent/> <any-child/> </any-service>
</route>
<config>
<libc stdout="/dev/log" stderr="/dev/log">
<libc
stdout="/dev/log" stderr="/dev/log" server_ip="10.0.2.55"
http_port="80"
>
<vfs> <dir name="dev"> <log/> </dir> </vfs>
</libc>
</config>
@ -151,7 +154,6 @@ set boot_modules {
# platform-specific modules
lappend_if [have_spec linux] boot_modules fb_sdl
lappend_if [have_spec ps2] boot_modules ps2_drv
append_platform_drv_boot_modules

View File

@ -18,6 +18,7 @@
#include <util/string.h>
#include <timer_session/connection.h>
#include <nic/packet_allocator.h>
#include <os/config.h>
extern "C" {
#include <lwip/sockets.h>
@ -31,6 +32,42 @@ extern "C" {
static const char *http_get_request =
"GET / HTTP/1.0\r\nHost: localhost:80\r\n\r\n"; /* simple HTTP request header */
using namespace Genode;
template <size_t N>
static Genode::String<N> read_string_attribute(Genode::Xml_node node, char const *attr,
Genode::String<N> default_value)
{
try {
char buf[N];
node.attribute(attr).value(buf, sizeof(buf));
return Genode::String<N>(Genode::Cstring(buf));
}
catch (...) {
return default_value; }
}
bool static_ip_config(uint32_t & ip, uint32_t & nm, uint32_t & gw)
{
enum { ADDR_STR_SZ = 16 };
Xml_node libc_node = config()->xml_node().sub_node("libc");
String<ADDR_STR_SZ> ip_str =
read_string_attribute<ADDR_STR_SZ>(libc_node, "ip_addr", String<ADDR_STR_SZ>());
String<ADDR_STR_SZ> nm_str =
read_string_attribute<ADDR_STR_SZ>(libc_node, "netmask", String<ADDR_STR_SZ>());
String<ADDR_STR_SZ> gw_str =
read_string_attribute<ADDR_STR_SZ>(libc_node, "gateway", String<ADDR_STR_SZ>());
ip = inet_addr(ip_str.string());
nm = inet_addr(nm_str.string());
gw = inet_addr(gw_str.string());
if (ip == INADDR_NONE || nm == INADDR_NONE || gw == INADDR_NONE) { return false; }
log("static ip config: ip=", ip_str, " nm=", nm_str, " gw=", gw_str);
return true;
}
/**
* The client thread simply loops endless,
@ -42,44 +79,72 @@ int main()
enum { BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128 };
static Timer::Connection _timer;
_timer.msleep(2000);
lwip_tcpip_init();
char serv_addr[] = "10.0.2.55";
uint32_t ip = 0;
uint32_t nm = 0;
uint32_t gw = 0;
bool static_ip = static_ip_config(ip, nm, gw);
if( lwip_nic_init(0, 0, 0, BUF_SIZE, BUF_SIZE))
{
Genode::error("got no IP address!");
return 0;
enum { ADDR_STR_SZ = 16 };
char serv_addr[ADDR_STR_SZ] = { 0 };
Xml_node libc_node = config()->xml_node().sub_node("libc");
try { libc_node.attribute("server_ip").value(serv_addr, ADDR_STR_SZ); }
catch(...) {
error("Missing \"server_ip\" attribute.");
throw Xml_node::Nonexistent_attribute();
}
if (static_ip) {
if (lwip_nic_init(ip, nm, gw, BUF_SIZE, BUF_SIZE)) {
error("We got no IP address!");
return 0;
}
} else {
if( lwip_nic_init(0, 0, 0, BUF_SIZE, BUF_SIZE))
{
error("got no IP address!");
return 0;
}
}
for(int j = 0; j != 5; ++j) {
_timer.msleep(2000);
Genode::log("Create new socket ...");
log("Create new socket ...");
int s = lwip_socket(AF_INET, SOCK_STREAM, 0 );
if (s < 0) {
Genode::error("no socket available!");
error("no socket available!");
continue;
}
Genode::log("Connect to server ...");
log("Connect to server ...");
unsigned port = 0;
try { libc_node.attribute("http_port").value(&port); }
catch (...) {
error("Missing \"http_port\" attribute.");
throw Xml_node::Nonexistent_attribute();
}
struct sockaddr_in addr;
addr.sin_port = htons(80);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(serv_addr);
if((lwip_connect(s, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
Genode::error("could not connect!");
error("Could not connect!");
lwip_close(s);
continue;
}
Genode::log("Send request...");
log("Send request...");
unsigned long bytes = lwip_send(s, (char*)http_get_request,
Genode::strlen(http_get_request), 0);
if ( bytes < 0 ) {
Genode::error("couldn't send request ...");
error("couldn't send request ...");
lwip_close(s);
continue;
}
@ -91,8 +156,7 @@ int main()
buflen = lwip_recv(s, buf, 1024, 0);
if(buflen > 0) {
buf[buflen] = 0;
Genode::log("Packet received!");
Genode::log("Packet content:\n", Genode::Cstring(buf));
log("Received \"", String<64>(buf), " ...\"");
} else
break;
}

View File

@ -22,6 +22,8 @@
#include <base/thread.h>
#include <util/string.h>
#include <nic/packet_allocator.h>
#include <os/config.h>
#include <base/snprintf.h>
/* LwIP includes */
extern "C" {
@ -35,8 +37,11 @@ extern "C" {
const static char http_html_hdr[] =
"HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"; /* HTTP response header */
const static char http_index_html[] =
"<html><head><title>Congrats!</title></head><body><h1>Welcome to our lwIP HTTP server!</h1><p>This is a small test page.</body></html>"; /* HTML page */
enum { HTTP_INDEX_HTML_SZ = 1024 };
static char http_index_html[HTTP_INDEX_HTML_SZ]; /* HTML page */
using namespace Genode;
/**
@ -52,7 +57,7 @@ void http_server_serve(int conn)
/* Read the data from the port, blocking if nothing yet there.
We assume the request (the part we care about) is in one packet */
buflen = lwip_recv(conn, buf, 1024, 0);
Genode::log("Packet received!");
log("Packet received!");
/* Ignore all receive errors */
if (buflen > 0) {
@ -66,7 +71,7 @@ void http_server_serve(int conn)
buf[3] == ' ' &&
buf[4] == '/' ) {
Genode::log("Will send response");
log("Will send response");
/* Send http header */
lwip_send(conn, http_html_hdr, Genode::strlen(http_html_hdr), 0);
@ -78,50 +83,104 @@ void http_server_serve(int conn)
}
template <size_t N>
static Genode::String<N> read_string_attribute(Genode::Xml_node node, char const *attr,
Genode::String<N> default_value)
{
try {
char buf[N];
node.attribute(attr).value(buf, sizeof(buf));
return Genode::String<N>(Genode::Cstring(buf));
}
catch (...) {
return default_value; }
}
int main()
{
using namespace Genode;
enum { BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128 };
int s;
lwip_tcpip_init();
enum { ADDR_STR_SZ = 16 };
uint32_t ip = 0;
uint32_t nm = 0;
uint32_t gw = 0;
unsigned port = 0;
Xml_node libc_node = config()->xml_node().sub_node("libc");
String<ADDR_STR_SZ> ip_addr_str =
read_string_attribute<ADDR_STR_SZ>(libc_node, "ip_addr", String<ADDR_STR_SZ>());
String<ADDR_STR_SZ> netmask_str =
read_string_attribute<ADDR_STR_SZ>(libc_node, "netmask", String<ADDR_STR_SZ>());
String<ADDR_STR_SZ> gateway_str =
read_string_attribute<ADDR_STR_SZ>(libc_node, "gateway", String<ADDR_STR_SZ>());
try { libc_node.attribute("http_port").value(&port); }
catch(...) {
error("Missing \"http_port\" attribute.");
throw Xml_node::Nonexistent_attribute();
}
log("static network interface: ip=", ip_addr_str, " nm=", netmask_str, " gw=", gateway_str);
ip = inet_addr(ip_addr_str.string());
nm = inet_addr(netmask_str.string());
gw = inet_addr(gateway_str.string());
if (ip == INADDR_NONE || nm == INADDR_NONE || gw == INADDR_NONE) {
error("Invalid network interface config.");
throw -1;
}
/* Initialize network stack */
if (lwip_nic_init(inet_addr("10.0.2.55"), inet_addr("255.255.255.0"),
inet_addr("10.0.2.1"), BUF_SIZE, BUF_SIZE)) {
Genode::error("got no IP address!");
if (lwip_nic_init(ip, nm, gw, BUF_SIZE, BUF_SIZE)) {
error("got no IP address!");
return -1;
}
Genode::log("Create new socket ...");
log("Create new socket ...");
if((s = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
Genode::error("no socket available!");
error("no socket available!");
return -1;
}
Genode::log("Now, I will bind ...");
Genode::snprintf(
http_index_html, HTTP_INDEX_HTML_SZ,
"<html><head></head><body>"
"<h1>HTTP server at %s:%u</h1>"
"<p>This is a small test page.</body></html>",
ip_addr_str.string(), port);
log("Now, I will bind ...");
struct sockaddr_in in_addr;
in_addr.sin_family = AF_INET;
in_addr.sin_port = htons(80);
in_addr.sin_port = htons(port);
in_addr.sin_addr.s_addr = INADDR_ANY;
if(lwip_bind(s, (struct sockaddr*)&in_addr, sizeof(in_addr))) {
Genode::error("bind failed!");
error("bind failed!");
return -1;
}
Genode::log("Now, I will listen ...");
log("Now, I will listen ...");
if(lwip_listen(s, 5)) {
Genode::error("listen failed!");
error("listen failed!");
return -1;
}
Genode::log("Start the server loop ...");
log("Start the server loop ...");
while(true) {
struct sockaddr addr;
socklen_t len = sizeof(addr);
int client = lwip_accept(s, &addr, &len);
if(client < 0) {
Genode::warning("invalid socket from accept!");
warning("invalid socket from accept!");
continue;
}
http_server_serve(client);

View File

@ -1,5 +1,5 @@
TARGET = test-lwip_httpsrv_static
LIBS = lwip libc
LIBS = lwip libc config
SRC_CC = main.cc
INC_DIR += $(REP_DIR)/src/lib/lwip/include