2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
21 * @file transport/test_plugin_transport_http.c
22 * @brief testcase for plugin_transport_http.c
23 * @author Matthias Wachs
27 #include "gnunet_constants.h"
28 #include "gnunet_getopt_lib.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_plugin_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_program_lib.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_service_lib.h"
37 #include "plugin_transport.h"
38 #include "gnunet_statistics_service.h"
39 #include "transport.h"
40 #include <curl/curl.h>
42 #define VERBOSE GNUNET_YES
43 #define DEBUG GNUNET_YES
45 #define PLUGIN libgnunet_plugin_transport_template
48 * How long until we give up on transmitting the message?
50 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
53 * How long until we give up on transmitting the message?
55 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
58 * How long between recieve and send?
60 #define WAIT_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
65 /* static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; */
70 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
75 static struct GNUNET_PeerIdentity my_identity;
80 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
86 struct GNUNET_SCHEDULER_Handle *sched;
89 * Our statistics handle.
91 struct GNUNET_STATISTICS_Handle *stats;
97 const struct GNUNET_CONFIGURATION_Handle *cfg;
100 * Number of neighbours we'd like to have.
102 static uint32_t max_connect_per_transport;
105 * Environment for this plugin.
107 static struct GNUNET_TRANSPORT_PluginEnvironment env;
110 *handle for the api provided by this plugin
112 static struct GNUNET_TRANSPORT_PluginFunctions *api;
115 * ID of the task controlling the testcase timeout
117 static GNUNET_SCHEDULER_TaskIdentifier ti_timeout;
119 static GNUNET_SCHEDULER_TaskIdentifier ti_send;
121 const struct GNUNET_PeerIdentity * p;
124 * Struct for plugin addresses
126 struct Plugin_Address
129 * Next field for linked list
131 struct Plugin_Address * next;
134 * buffer containing data to send
139 * amount of data to sent
144 struct Plugin_Address * addr_head;
147 * Did the test pass or fail?
149 static int fail_notify_address;
151 * Did the test pass or fail?
153 static int fail_notify_address_count;
156 * Did the test pass or fail?
158 static int fail_pretty_printer;
161 * Did the test pass or fail?
163 static int fail_pretty_printer_count;
166 * Did the test pass or fail?
168 static int fail_addr_to_str;
171 * Did the test pass or fail?
176 * Recieved message already returned to sender?
186 if (ti_send != GNUNET_SCHEDULER_NO_TASK)
188 GNUNET_SCHEDULER_cancel(sched,ti_send);
189 ti_send = GNUNET_SCHEDULER_NO_TASK;
192 if (ti_timeout != GNUNET_SCHEDULER_NO_TASK)
194 GNUNET_SCHEDULER_cancel(sched,ti_timeout);
195 ti_timeout = GNUNET_SCHEDULER_NO_TASK;
197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unloading http plugin\n");
198 GNUNET_assert (NULL == GNUNET_PLUGIN_unload ("libgnunet_plugin_transport_http", api));
200 GNUNET_SCHEDULER_shutdown(sched);
201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exiting testcase\n");
207 * Continuation called after plugin send message
210 * @result GNUNET_OK or GNUNET_SYSERR
212 static void task_send_cont (void *cls,
213 const struct GNUNET_PeerIdentity * target,
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message was sent!\n");
222 * Task sending recieved message back to peer
227 task_send (void *cls,
228 const struct GNUNET_SCHEDULER_TaskContext *tc)
230 ti_timeout = GNUNET_SCHEDULER_NO_TASK;
231 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
234 if (GNUNET_YES==sent)
237 struct GNUNET_MessageHeader * msg = cls;
238 unsigned int len = ntohs(msg->size);
239 const char * msgc = (const char *) msg;
241 api->send(api->cls, p, msgc, len, 0, TIMEOUT, NULL,NULL, 0, GNUNET_NO, &task_send_cont, NULL);
247 * Recieves messages from plugin, in real world transport
249 static struct GNUNET_TIME_Relative
251 const struct GNUNET_PeerIdentity * peer,
252 const struct GNUNET_MessageHeader * message,
254 struct Session *session,
255 const char *sender_address,
256 uint16_t sender_address_len)
258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testcase recieved new message from peer `%s' with type %u and length %u\n", GNUNET_i2s(peer),ntohs(message->type),ntohs(message->size));
260 /* take recieved message and send it back to peer */
262 void * c = (void *) message;
263 ti_send =GNUNET_SCHEDULER_add_delayed (sched, WAIT_INTERVALL, &task_send, c);
265 return GNUNET_TIME_UNIT_ZERO;
270 * Network format for IPv4 addresses.
272 struct IPv4HttpAddress
275 * IPv4 address, in network byte order.
280 * Port number, in network byte order.
288 * Network format for IPv6 addresses.
290 struct IPv6HttpAddress
295 struct in6_addr ipv6_addr;
298 * Port number, in network byte order.
305 * Plugin notifies transport (aka testcase) about its addresses
308 notify_address (void *cls,
312 struct GNUNET_TIME_Relative expires)
314 char * address = NULL;
316 struct Plugin_Address * pl_addr;
317 struct Plugin_Address * cur;
319 if (addrlen == (sizeof (struct IPv4HttpAddress)))
321 address = GNUNET_malloc (INET_ADDRSTRLEN);
322 inet_ntop(AF_INET, (struct in_addr *) addr,address,INET_ADDRSTRLEN);
323 port = ntohs(((struct IPv4HttpAddress *) addr)->u_port);
326 if (addrlen == (sizeof (struct IPv6HttpAddress)))
328 address = GNUNET_malloc (INET6_ADDRSTRLEN);
329 inet_ntop(AF_INET6, (struct in6_addr *) addr,address,INET6_ADDRSTRLEN);
330 port = ntohs(((struct IPv6HttpAddress *) addr)->u6_port);
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Transport plugin notification for address: `%s':%u\n"),address,port);
334 pl_addr = GNUNET_malloc (sizeof (struct Plugin_Address) );
335 pl_addr->addrlen = addrlen;
336 pl_addr->addr = GNUNET_malloc(addrlen);
337 memcpy(pl_addr->addr,addr,addrlen);
338 pl_addr->next = NULL;
340 if ( NULL == addr_head)
347 while (NULL != cur->next)
354 fail_notify_address_count++;
355 fail_notify_address = GNUNET_NO;
359 * Setup plugin environment
362 setup_plugin_environment ()
367 env.my_identity = &my_identity;
369 env.receive = &receive;
370 env.notify_address = ¬ify_address;
371 env.max_connections = max_connect_per_transport;
376 * Task shutting down testcase if it a timeout occurs
379 task_timeout (void *cls,
380 const struct GNUNET_SCHEDULER_TaskContext *tc)
382 ti_timeout = GNUNET_SCHEDULER_NO_TASK;
383 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testcase timeout\n");
392 static void pretty_printer_cb (void *cls,
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Plugin returnedp pretty address: `%s'\n",address);
398 fail_pretty_printer_count++;
406 * @param s scheduler to use
407 * @param c configuration to use
411 struct GNUNET_SCHEDULER_Handle *s,
413 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
419 unsigned long long tneigh;
420 struct Plugin_Address * cur;
421 struct Plugin_Address * tmp;
422 const char * addr_str;
423 unsigned int count_str_addr;
424 unsigned int suggest_res;
426 fail_pretty_printer = GNUNET_YES;
427 fail_notify_address = GNUNET_YES;
428 fail_addr_to_str = GNUNET_YES;
431 /* parse configuration */
433 GNUNET_CONFIGURATION_get_value_number (c,
438 GNUNET_CONFIGURATION_get_value_filename (c,
440 "HOSTKEY", &keyfile)))
442 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
444 ("Transport service is lacking key configuration settings. Exiting.\n"));
445 GNUNET_SCHEDULER_shutdown (s);
449 max_connect_per_transport = (uint32_t) tneigh;
450 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
451 GNUNET_free (keyfile);
452 if (my_private_key == NULL)
454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
455 _("Transport service could not access hostkey. Exiting.\n"));
456 GNUNET_SCHEDULER_shutdown (s);
460 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
461 GNUNET_CRYPTO_hash (&my_public_key,
462 sizeof (my_public_key), &my_identity.hashPubKey);
464 /* load plugins... */
465 setup_plugin_environment ();
466 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading HTTP transport plugin `%s'\n"),"libgnunet_plugin_transport_http");
467 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_http");
468 api = GNUNET_PLUGIN_load (libname, &env);
469 GNUNET_free (libname);
472 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
473 _("Failed to load transport plugin for http\n"));
478 ti_timeout = GNUNET_SCHEDULER_add_delayed (sched, TEST_TIMEOUT, &task_timeout, NULL);
480 /* testing plugin functionality */
481 GNUNET_assert (0!=fail_notify_address_count);
482 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport plugin returned %u addresses to connect to\n"), fail_notify_address_count);
484 /* testing pretty printer with all addresses obtained from the plugin*/
485 while (addr_head != NULL)
489 api->address_pretty_printer (NULL,"http",cur->addr,cur->addrlen,GNUNET_NO,TEST_TIMEOUT,&pretty_printer_cb,NULL);
490 addr_str = api->address_to_string (NULL,cur->addr,cur->addrlen);
491 suggest_res = api->check_address (NULL,cur->addr,cur->addrlen);
493 GNUNET_assert (GNUNET_OK == suggest_res);
494 GNUNET_assert (NULL != addr_str);
497 tmp = addr_head->next;
498 GNUNET_free (addr_head->addr);
499 GNUNET_free (addr_head);
500 GNUNET_free ((char *) addr_str);
503 GNUNET_assert (fail_pretty_printer_count==fail_notify_address_count);
504 GNUNET_assert (fail_pretty_printer_count==count_str_addr);
505 fail_pretty_printer=GNUNET_NO;
506 fail_addr_to_str=GNUNET_NO;
508 /* Suggesting addresses with wrong port*/
509 struct IPv4HttpAddress failing_addr;
510 failing_addr.ipv4_addr = INADDR_LOOPBACK;
511 failing_addr.u_port = 0;
512 suggest_res = api->check_address (NULL,&failing_addr,sizeof (struct IPv4HttpAddress));
513 GNUNET_assert (GNUNET_SYSERR == suggest_res);
515 /* Suggesting addresses with wrong size*/
516 failing_addr.ipv4_addr = INADDR_LOOPBACK;
517 failing_addr.u_port = 0;
518 suggest_res = api->check_address (NULL,&failing_addr,sizeof (struct IPv6HttpAddress));
519 GNUNET_assert (GNUNET_SYSERR == suggest_res);
521 /* Suggesting addresses with wrong address*/
522 failing_addr.ipv4_addr = 0;
523 failing_addr.u_port = 12389;
524 suggest_res = api->check_address (NULL,&failing_addr,sizeof (struct IPv4HttpAddress));
525 GNUNET_assert (GNUNET_SYSERR == suggest_res);
527 /* testing finished, shutting down */
528 if ((fail_notify_address == GNUNET_NO) && (fail_pretty_printer == GNUNET_NO) && (fail_addr_to_str == GNUNET_NO) )
538 * The main function for the transport service.
540 * @param argc number of arguments from the command line
541 * @param argv command line arguments
542 * @return 0 ok, 1 on error
545 main (int argc, char *const *argv)
548 static struct GNUNET_GETOPT_CommandLineOption options[] = {
549 GNUNET_GETOPT_OPTION_END
552 char *const argv_prog[] = {
553 "test_plugin_transport_http",
555 "test_plugin_transport_data_http.conf",
564 GNUNET_log_setup ("test_plugin_transport_http",
573 GNUNET_PROGRAM_run (5,
575 "test_plugin_transport_http",
576 "testcase", options, &run, NULL)) ? GNUNET_NO : GNUNET_YES;
578 GNUNET_DISK_directory_remove ("/tmp/test_plugin_transport_http");
583 /* end of test_plugin_transport_http.c */