genode/repos/libports/src/test/lwip/http_clnt/main.cc

138 lines
3.6 KiB
C++

/*
* \brief HTTP client test
* \author Ivan Loskutov
* \author Martin Stein
* \date 2012-12-21
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-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 <libc/component.h>
#include <nic/packet_allocator.h>
#include <timer_session/connection.h>
#include <util/string.h>
/* Libc includes */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace Genode;
void close_socket(Libc::Env &env, int sd)
{
if (::shutdown(sd, SHUT_RDWR)) {
error("failed to shutdown");
env.parent().exit(-1);
}
if (::close(sd)) {
error("failed to close");
env.parent().exit(-1);
}
}
static void test(Libc::Env &env)
{
using Ipv4_string = String<16>;
enum { NR_OF_REPLIES = 5 };
enum { NR_OF_TRIALS = 15 };
/* read component configuration */
Attached_rom_dataspace config_rom { env, "config" };
Xml_node config_node { config_rom.xml() };
Ipv4_string const srv_ip { config_node.attribute_value("server_ip", Ipv4_string("0.0.0.0")) };
uint16_t const srv_port { config_node.attribute_value("server_port", (uint16_t)0) };
/* construct server socket address */
struct sockaddr_in srv_addr;
srv_addr.sin_port = htons(srv_port);
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = inet_addr(srv_ip.string());
/* try several times to request a reply */
for (unsigned trial_cnt = 0, reply_cnt = 0; trial_cnt < NR_OF_TRIALS;
trial_cnt++)
{
/* pause a while between each trial */
usleep(1000000);
/* create socket */
int sd = ::socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) {
error("failed to create socket");
continue;
}
/* connect to server */
if (::connect(sd, (struct sockaddr *)&srv_addr, sizeof(srv_addr))) {
error("Failed to connect to server");
close_socket(env, sd);
continue;
}
/* send request */
char const *req = "GET / HTTP/1.0\r\nHost: localhost:80\r\n\r\n";
size_t const req_sz = Genode::strlen(req);
if (::send(sd, req, req_sz, 0) != (int)req_sz) {
error("failed to send request");
close_socket(env, sd);
continue;
}
/* receive reply */
enum { REPLY_BUF_SZ = 1024 };
char reply_buf[REPLY_BUF_SZ];
size_t reply_sz = 0;
bool reply_failed = false;
char const *reply_end = "</html>";
size_t const reply_end_sz = Genode::strlen(reply_end);
for (; reply_sz <= REPLY_BUF_SZ; ) {
char *rcv_buf = &reply_buf[reply_sz];
size_t const rcv_buf_sz = REPLY_BUF_SZ - reply_sz;
signed long rcv_sz = ::recv(sd, rcv_buf, rcv_buf_sz, 0);
if (rcv_sz < 0) {
reply_failed = true;
break;
}
reply_sz += rcv_sz;
if (reply_sz >= reply_end_sz) {
if (!strcmp(&reply_buf[reply_sz - reply_end_sz], reply_end, reply_end_sz)) {
break; }
}
}
/* ignore failed replies */
if (reply_failed) {
error("failed to receive reply");
close_socket(env, sd);
continue;
}
/* handle reply */
reply_buf[reply_sz] = 0;
log("Received \"", Cstring(reply_buf), "\"");
if (++reply_cnt == NR_OF_REPLIES) {
log("Test done");
env.parent().exit(0);
}
/* close socket and retry */
close_socket(env, sd);
}
log("Test failed");
env.parent().exit(-1);
}
void Libc::Component::construct(Libc::Env &env) { with_libc([&] () { test(env); }); }