2012-12-21 09:06:18 +01:00
|
|
|
/*
|
|
|
|
* \brief HTTP client test
|
|
|
|
* \author Ivan Loskutov
|
|
|
|
* \date 2012-12-21
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 Ksys Labs LLC
|
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
#include <base/log.h>
|
2012-12-21 09:06:18 +01:00
|
|
|
#include <base/thread.h>
|
|
|
|
#include <util/string.h>
|
|
|
|
#include <timer_session/connection.h>
|
2013-09-23 15:58:45 +02:00
|
|
|
#include <nic/packet_allocator.h>
|
2016-08-15 11:56:29 +02:00
|
|
|
#include <os/config.h>
|
2012-12-21 09:06:18 +01:00
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include <lwip/sockets.h>
|
|
|
|
#include <lwip/api.h>
|
|
|
|
#include <netif/etharp.h>
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <lwip/genode.h>
|
|
|
|
|
|
|
|
|
|
|
|
static const char *http_get_request =
|
|
|
|
"GET / HTTP/1.0\r\nHost: localhost:80\r\n\r\n"; /* simple HTTP request header */
|
|
|
|
|
2016-08-15 11:56:29 +02:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
2016-11-03 12:24:28 +01:00
|
|
|
template <Genode::size_t N>
|
2016-08-15 11:56:29 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-12-21 09:06:18 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The client thread simply loops endless,
|
|
|
|
* and sends as much 'http get' requests as possible,
|
|
|
|
* printing out the response.
|
|
|
|
*/
|
|
|
|
int main()
|
|
|
|
{
|
2013-09-23 15:58:45 +02:00
|
|
|
enum { BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128 };
|
|
|
|
|
2012-12-21 09:06:18 +01:00
|
|
|
static Timer::Connection _timer;
|
2016-08-15 11:56:29 +02:00
|
|
|
_timer.msleep(2000);
|
2012-12-21 09:06:18 +01:00
|
|
|
lwip_tcpip_init();
|
|
|
|
|
2016-08-15 11:56:29 +02:00
|
|
|
uint32_t ip = 0;
|
|
|
|
uint32_t nm = 0;
|
|
|
|
uint32_t gw = 0;
|
|
|
|
bool static_ip = static_ip_config(ip, nm, gw);
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2012-12-21 09:06:18 +01:00
|
|
|
|
2016-08-15 11:56:29 +02:00
|
|
|
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;
|
|
|
|
}
|
2012-12-21 09:06:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for(int j = 0; j != 5; ++j) {
|
|
|
|
_timer.msleep(2000);
|
|
|
|
|
|
|
|
|
2016-08-15 11:56:29 +02:00
|
|
|
log("Create new socket ...");
|
2012-12-21 09:06:18 +01:00
|
|
|
int s = lwip_socket(AF_INET, SOCK_STREAM, 0 );
|
|
|
|
if (s < 0) {
|
2016-08-15 11:56:29 +02:00
|
|
|
error("no socket available!");
|
2012-12-21 09:06:18 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-15 11:56:29 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2012-12-21 09:06:18 +01:00
|
|
|
struct sockaddr_in addr;
|
2016-08-15 11:56:29 +02:00
|
|
|
addr.sin_port = htons(port);
|
2012-12-21 09:06:18 +01:00
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
addr.sin_addr.s_addr = inet_addr(serv_addr);
|
|
|
|
|
|
|
|
if((lwip_connect(s, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
|
2016-08-15 11:56:29 +02:00
|
|
|
error("Could not connect!");
|
2012-12-21 09:06:18 +01:00
|
|
|
lwip_close(s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-15 11:56:29 +02:00
|
|
|
log("Send request...");
|
2012-12-21 09:06:18 +01:00
|
|
|
unsigned long bytes = lwip_send(s, (char*)http_get_request,
|
|
|
|
Genode::strlen(http_get_request), 0);
|
|
|
|
if ( bytes < 0 ) {
|
2016-08-15 11:56:29 +02:00
|
|
|
error("couldn't send request ...");
|
2012-12-21 09:06:18 +01:00
|
|
|
lwip_close(s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Receive http header and content independently in 2 packets */
|
|
|
|
for(int i=0; i<2; i++) {
|
|
|
|
char buf[1024];
|
|
|
|
ssize_t buflen;
|
|
|
|
buflen = lwip_recv(s, buf, 1024, 0);
|
|
|
|
if(buflen > 0) {
|
|
|
|
buf[buflen] = 0;
|
2016-08-15 11:56:29 +02:00
|
|
|
log("Received \"", String<64>(buf), " ...\"");
|
2012-12-21 09:06:18 +01:00
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close socket */
|
|
|
|
lwip_close(s);
|
|
|
|
}
|
|
|
|
|
2016-11-25 15:57:40 +01:00
|
|
|
log("Test done");
|
2012-12-21 09:06:18 +01:00
|
|
|
return 0;
|
|
|
|
}
|