(no commit message)
[oweals/gnunet.git] / src / transport / test_plugin_transport_http.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20 /**
21  * @file transport/test_plugin_transport_http.c
22  * @brief testcase for plugin_transport_http.c
23  * @author Matthias Wachs
24  */
25
26 #include "platform.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_common.h"
29 #include "gnunet_getopt_lib.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_os_lib.h"
32 #include "gnunet_peerinfo_service.h"
33 #include "gnunet_plugin_lib.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_program_lib.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_crypto_lib.h"
39
40 #include "plugin_transport.h"
41 #include "gnunet_statistics_service.h"
42 #include "transport.h"
43 #include <curl/curl.h>
44
45 #define VERBOSE GNUNET_YES
46 #define DEBUG GNUNET_NO
47 #define DEBUG_CURL GNUNET_YES
48 #define HTTP_BUFFER_SIZE 2048
49
50 #define PLUGIN libgnunet_plugin_transport_template
51
52 /**
53  * How long until we give up on transmitting the message?
54  */
55 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
56
57 /**
58  * How long until we give up on transmitting the message?
59  */
60 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
61
62 /**
63  * How long between recieve and send?
64  */
65 #define WAIT_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
66
67
68
69 /**
70  *  Struct for plugin addresses
71  */
72 struct Plugin_Address
73 {
74   /**
75    * Next field for linked list
76    */
77   struct Plugin_Address * next;
78
79   /**
80    * buffer containing data to send
81    */
82   void * addr;
83
84   /**
85    * amount of data to sent
86    */
87   size_t addrlen;
88 };
89
90 /**
91  *  Message to send using http
92  */
93 struct HTTP_Message
94 {
95   /**
96    * buffer
97    */
98   unsigned char buf[HTTP_BUFFER_SIZE];
99
100   /**
101    * current position in buffer
102    */
103   size_t pos;
104
105   /**
106    * buffer size
107    */
108   size_t size;
109
110   /**
111    * data size
112    */
113   size_t len;
114 };
115
116
117 /**
118  *  Struct for plugin addresses
119  */
120 struct HTTP_Transfer
121 {
122   /**
123    * amount of bytes we recieved
124    */
125   size_t data_size;
126
127   /**
128    * buffer for http transfers
129    */
130   unsigned char buf[HTTP_BUFFER_SIZE];
131
132   /**
133    * buffer size this transfer
134    */
135   size_t size;
136
137   /**
138    * amount of bytes we recieved
139    */
140   size_t pos;
141
142   /**
143    * HTTP Header result for transfer
144    */
145   unsigned int http_result_code;
146
147   /**
148    * did the test fail?
149    */
150   unsigned int test_failed;
151
152   /**
153    * was this test already executed?
154    */
155   unsigned int test_executed;
156 };
157
158
159 /**
160  * Network format for IPv4 addresses.
161  */
162 struct IPv4HttpAddress
163 {
164   /**
165    * IPv4 address, in network byte order.
166    */
167   uint32_t ipv4_addr;
168
169   /**
170    * Port number, in network byte order.
171    */
172   uint16_t u_port;
173
174 };
175
176
177 /**
178  * Network format for IPv6 addresses.
179  */
180 struct IPv6HttpAddress
181 {
182   /**
183    * IPv6 address.
184    */
185   struct in6_addr ipv6_addr;
186
187   /**
188    * Port number, in network byte order.
189    */
190   uint16_t u6_port;
191
192 };
193
194
195 /**
196  * Our public key.
197  */
198 /* static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; */
199
200 /**
201  * Our public key.
202  */
203 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
204
205 /**
206  * Our identity.
207  */
208 static struct GNUNET_PeerIdentity my_identity;
209
210 /**
211  * Our private key.
212  */
213 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
214
215 /**
216  * Peer's port
217  */
218 static long long unsigned int port;
219
220 /**
221  * Peer's port
222  */
223 static char * test_addr;
224
225 /**
226  * Our scheduler.
227  */
228 struct GNUNET_SCHEDULER_Handle *sched;
229
230 /**
231  * Our statistics handle.
232  */
233 struct GNUNET_STATISTICS_Handle *stats;
234
235
236 /**
237  * Our configuration.
238  */
239 const struct GNUNET_CONFIGURATION_Handle *cfg;
240
241 /**
242  * Number of neighbours we'd like to have.
243  */
244 static uint32_t max_connect_per_transport;
245
246 /**
247  * Environment for this plugin.
248  */
249 static struct GNUNET_TRANSPORT_PluginEnvironment env;
250
251 /**
252  *handle for the api provided by this plugin
253  */
254 static struct GNUNET_TRANSPORT_PluginFunctions *api;
255
256 /**
257  * ID of the task controlling the testcase timeout
258  */
259 static GNUNET_SCHEDULER_TaskIdentifier ti_timeout;
260
261 static GNUNET_SCHEDULER_TaskIdentifier ti_send;
262
263 //const struct GNUNET_PeerIdentity * p;
264
265 /**
266  * buffer for data to send
267  */
268 static struct HTTP_Message buffer_out;
269
270 /**
271  * buffer for data to recieve
272  */
273 static struct HTTP_Message buffer_in;
274
275
276 struct Plugin_Address * addr_head;
277
278 /**
279  * Did the test pass or fail?
280  */
281 static int fail_notify_address;
282 /**
283  * Did the test pass or fail?
284  */
285 static int fail_notify_address_count;
286
287 /**
288  * Did the test pass or fail?
289  */
290 static int fail_pretty_printer;
291
292 /**
293  * Did the test pass or fail?
294  */
295 static int fail_pretty_printer_count;
296
297 /**
298  * Did the test pass or fail?
299  */
300 static int fail_addr_to_str;
301
302 /**
303  * No. of msgs transmitted successfully to local addresses
304  */
305 static int fail_msgs_transmited_to_local_addrs;
306
307 /**
308  * Test: transmit msg of max. size
309  */
310 static int fail_msg_transmited_bigger_max_size;
311
312 /**
313  * Test: transmit msg of max. size
314  */
315 static int fail_msg_transmited_max_size;
316
317 /**
318  * Test: transmit 2 msgs. in in send operation
319  */
320 static int fail_multiple_msgs_in_transmission;
321
322 /**
323  * Test: connect to peer without peer identification
324  */
325 static struct HTTP_Transfer test_no_ident;
326
327 /**
328  * Test: connect to peer without peer identification
329  */
330 static struct HTTP_Transfer test_too_short_ident;
331
332 /**
333  * Test: connect to peer without peer identification
334  */
335 static struct HTTP_Transfer test_too_long_ident;
336
337 /**
338  * Test: connect to peer with valid peer identification
339  */
340 static struct HTTP_Transfer test_valid_ident;
341
342 /**
343  * Did the test pass or fail?
344  */
345 static int fail;
346
347 /**
348  * Number of local addresses
349  */
350 static unsigned int count_str_addr;
351
352 CURL *curl_handle;
353
354 /**
355  * cURL Multihandle
356  */
357 static CURLM *multi_handle;
358
359 /**
360  * The task sending data
361  */
362 static GNUNET_SCHEDULER_TaskIdentifier http_task_send;
363
364 /**
365  * Shutdown testcase
366  */
367 static void
368 shutdown_clean ()
369 {
370   struct Plugin_Address * cur;
371   struct Plugin_Address * tmp;
372
373   /* Evaluate results  */
374   fail = 0;
375   if ((fail_notify_address == GNUNET_YES) || (fail_pretty_printer == GNUNET_YES) || (fail_addr_to_str == GNUNET_YES))
376   {
377     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test plugin functions failed\n");
378     fail = 1;
379   }
380   if ((test_no_ident.test_failed == GNUNET_YES) || (test_too_short_ident.test_failed == GNUNET_YES) || (test_too_long_ident.test_failed == GNUNET_YES) || (test_valid_ident.test_failed == GNUNET_YES))
381   {
382     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test connect with wrong data failed\n");
383     fail = 1;
384   }
385   if ((fail_msgs_transmited_to_local_addrs != count_str_addr) || (fail_multiple_msgs_in_transmission != 2) || (fail_msg_transmited_max_size == GNUNET_YES))
386   {
387     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test sending with plugin failed\n");
388     fail = 1;
389   }
390   if (fail != 1)
391   {
392     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All tests successful\n");
393   }
394
395   curl_multi_cleanup(multi_handle);
396
397   if (NULL != curl_handle)
398     curl_easy_cleanup (curl_handle);
399
400   /* cleaning addresses */
401   while (addr_head != NULL)
402   {
403     cur = addr_head;
404     tmp = addr_head->next;
405     GNUNET_free (addr_head->addr);
406     GNUNET_free (addr_head);
407     addr_head=tmp;
408   }
409
410   if (ti_send != GNUNET_SCHEDULER_NO_TASK)
411   {
412     GNUNET_SCHEDULER_cancel(sched,ti_send);
413     ti_send = GNUNET_SCHEDULER_NO_TASK;
414   }
415
416   if (http_task_send != GNUNET_SCHEDULER_NO_TASK)
417   {
418     GNUNET_SCHEDULER_cancel(sched,http_task_send);
419     http_task_send = GNUNET_SCHEDULER_NO_TASK;
420   }
421
422   if (ti_timeout != GNUNET_SCHEDULER_NO_TASK)
423   {
424     GNUNET_SCHEDULER_cancel(sched,ti_timeout);
425     ti_timeout = GNUNET_SCHEDULER_NO_TASK;
426   }
427
428   GNUNET_free(test_addr);
429   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unloading http plugin\n");
430   GNUNET_assert (NULL == GNUNET_PLUGIN_unload ("libgnunet_plugin_transport_http", api));
431
432   GNUNET_SCHEDULER_shutdown(sched);
433   GNUNET_DISK_directory_remove ("/tmp/test_plugin_transport_http");
434
435   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exiting testcase\n");
436   exit(fail);
437   return;
438 }
439
440
441 /**
442  * Continuation called after plugin send message
443  * @cls closure
444  * @target target
445  * @result GNUNET_OK or GNUNET_SYSERR
446  */
447
448 static void task_send_cont (void *cls,
449                             const struct GNUNET_PeerIdentity * target,
450                             int result)
451 {
452   struct Plugin_Address * tmp_addr;
453   tmp_addr = addr_head;
454
455   if ((cls == &fail_msg_transmited_bigger_max_size) && (result == GNUNET_SYSERR))
456   {
457     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message bigger max msg size was not sent!\n");
458     fail_msg_transmited_bigger_max_size = GNUNET_NO;
459     return;
460   }
461
462   if ((cls == &fail_msg_transmited_max_size) && (result == GNUNET_OK))
463   {
464     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message with max msg size succesfully sent!\n",fail_msgs_transmited_to_local_addrs);
465     fail_msg_transmited_max_size = GNUNET_NO;
466     //shutdown_clean();
467   }
468 }
469
470
471 static void run_connection_tests( int );
472
473 /**
474  * Recieves messages from plugin, in real world transport
475  */
476 static struct GNUNET_TIME_Relative
477 receive (void *cls,
478          const struct GNUNET_PeerIdentity * peer,
479          const struct GNUNET_MessageHeader * message,
480          uint32_t distance,
481          struct Session *session,
482          const char *sender_address,
483          uint16_t sender_address_len)
484 {
485   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));
486
487   if ((ntohs(message->type)>=10) && (ntohs(message->type)<=20))
488   {
489     fail_msgs_transmited_to_local_addrs++;
490     if (fail_msgs_transmited_to_local_addrs == count_str_addr)
491       run_connection_tests(2);
492   }
493
494   if ((ntohs(message->type)==40) || (ntohs(message->type)==41))
495   {
496     fail_multiple_msgs_in_transmission ++;
497   }
498
499   if (ntohs(message->size) == GNUNET_SERVER_MAX_MESSAGE_SIZE-1)
500   {
501     fail_msg_transmited_max_size = GNUNET_NO;
502     shutdown_clean();
503   }
504
505   return GNUNET_TIME_UNIT_ZERO;
506 }
507
508 static size_t send_function (void *stream, size_t size, size_t nmemb, void *ptr)
509 {
510   unsigned int len;
511
512   len = buffer_out.len;
513
514   if (( buffer_out.pos == len) || (len > (size * nmemb)))
515     return 0;
516   memcpy(stream, buffer_out.buf, len);
517   buffer_out.pos = len;
518   return len;
519 }
520
521 static size_t recv_function (void *ptr, size_t size, size_t nmemb, void *ctx)
522 {
523
524   if (buffer_in.pos + size * nmemb > buffer_in.size)
525     return 0;                   /* overflow */
526
527   buffer_in.len = size * nmemb;
528   memcpy (&buffer_in.buf[buffer_in.pos], ptr, size * nmemb);
529   buffer_in.pos += size * nmemb;
530   buffer_in.len = buffer_in.pos;
531   buffer_in.buf[buffer_in.pos] = '\0';
532   return buffer_in.pos;
533 }
534
535 static size_t header_function( void *ptr, size_t size, size_t nmemb, void *stream)
536 {
537   struct HTTP_Transfer * res = (struct HTTP_Transfer *) stream;
538   char * tmp;
539   unsigned int len = size * nmemb;
540
541   tmp = GNUNET_malloc (  len+1 );
542   memcpy(tmp,ptr,len);
543   if (tmp[len-2] == 13)
544     tmp[len-2]= '\0';
545 #if DEBUG_CURL
546   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s'\n",tmp);
547 #endif
548   if (0==strcmp (tmp,"HTTP/1.1 100 Continue"))
549   {
550     res->http_result_code=100;
551   }
552   if (0==strcmp (tmp,"HTTP/1.1 200 OK"))
553   {
554     res->http_result_code=200;
555   }
556   if (0==strcmp (tmp,"HTTP/1.1 400 Bad Request"))
557   {
558     res->http_result_code=400;
559   }
560   if (0==strcmp (tmp,"HTTP/1.1 404 Not Found"))
561   {
562     res->http_result_code=404;
563   }
564   if (0==strcmp (tmp,"HTTP/1.1 413 Request entity too large"))
565   {
566     res->http_result_code=413;
567   }
568
569   GNUNET_free (tmp);
570   return size * nmemb;
571 }
572
573 static size_t send_prepare( struct HTTP_Transfer * result);
574
575 static void run_connection_tests( );
576
577 static void send_execute (void *cls,
578              const struct GNUNET_SCHEDULER_TaskContext *tc)
579 {
580   struct HTTP_Transfer *res;
581
582   int running;
583   struct CURLMsg *msg;
584   CURLMcode mret;
585
586   res = (struct HTTP_Transfer *) cls;
587   http_task_send = GNUNET_SCHEDULER_NO_TASK;
588   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
589     return;
590
591   do
592     {
593       running = 0;
594       mret = curl_multi_perform (multi_handle, &running);
595       if (running == 0)
596         {
597           do
598             {
599
600               msg = curl_multi_info_read (multi_handle, &running);
601               if (msg == NULL)
602                 break;
603               /* get session for affected curl handle */
604               //cs = find_session_by_curlhandle (msg->easy_handle);
605               //GNUNET_assert ( cs != NULL );
606               switch (msg->msg)
607                 {
608
609                 case CURLMSG_DONE:
610                   if ( (msg->data.result != CURLE_OK) &&
611                        (msg->data.result != CURLE_GOT_NOTHING) )
612                     {
613
614                     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
615                                _("curl failed for `%s' at %s:%d: `%s'\n"),
616                                "curl_multi_perform",
617                                __FILE__,
618                                __LINE__,
619                                curl_easy_strerror (msg->data.result));
620                     /* sending msg failed*/
621                     curl_easy_cleanup(curl_handle);
622                     curl_handle=NULL;
623
624                     run_connection_tests(1);
625                     }
626                   if (res == &test_no_ident)
627                   {
628                     if  ((res->http_result_code==404) && (buffer_in.len==208))
629                     {
630                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer without any peer identification: test passed\n"));
631                       res->test_failed = GNUNET_NO;
632                     }
633                     else
634                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer without any peer identification: test failed\n"));
635                   }
636                   if (res == &test_too_short_ident)
637                   {
638                     if  ((res->http_result_code==404) && (buffer_in.len==208))
639                     {
640                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too short peer identification: test passed\n"));
641                       res->test_failed = GNUNET_NO;
642                     }
643                     else
644                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too short peer identification: test failed\n"));
645                   }
646                   if (res == &test_too_long_ident)
647                   {
648                     if  ((res->http_result_code==404) && (buffer_in.len==208))
649                       {
650                         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too long peer identification: test passed\n"));
651                       res->test_failed = GNUNET_NO;
652                       }
653                     else
654                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too long peer identification: test failed\n"));
655                   }
656                   if (res == &test_valid_ident)
657                   {
658                     if  ((res->http_result_code==200))
659                     {
660                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with valid peer identification: test passed\n"));
661                       res->test_failed = GNUNET_NO;
662                     }
663                     else
664                       GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with valid peer identification: test failed\n"));
665                   }
666                   curl_easy_cleanup(curl_handle);
667                   curl_handle=NULL;
668
669                   run_connection_tests(1);
670                   return;
671                 default:
672                   break;
673                 }
674
675             }
676           while ( (running > 0) );
677         }
678     }
679   while (mret == CURLM_CALL_MULTI_PERFORM);
680   send_prepare(cls);
681 }
682
683 /**
684  * Function setting up file descriptors and scheduling task to run
685  * @param ses session to send data to
686  * @return bytes sent to peer
687  */
688 static size_t send_prepare( struct HTTP_Transfer * result)
689 {
690   fd_set rs;
691   fd_set ws;
692   fd_set es;
693   int max;
694   struct GNUNET_NETWORK_FDSet *grs;
695   struct GNUNET_NETWORK_FDSet *gws;
696   long to;
697   CURLMcode mret;
698
699   max = -1;
700   FD_ZERO (&rs);
701   FD_ZERO (&ws);
702   FD_ZERO (&es);
703   mret = curl_multi_fdset (multi_handle, &rs, &ws, &es, &max);
704   if (mret != CURLM_OK)
705     {
706       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
707                   _("%s failed at %s:%d: `%s'\n"),
708                   "curl_multi_fdset", __FILE__, __LINE__,
709                   curl_multi_strerror (mret));
710       return -1;
711     }
712   mret = curl_multi_timeout (multi_handle, &to);
713   if (mret != CURLM_OK)
714     {
715       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
716                   _("%s failed at %s:%d: `%s'\n"),
717                   "curl_multi_timeout", __FILE__, __LINE__,
718                   curl_multi_strerror (mret));
719       return -1;
720     }
721
722   grs = GNUNET_NETWORK_fdset_create ();
723   gws = GNUNET_NETWORK_fdset_create ();
724   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
725   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
726   http_task_send = GNUNET_SCHEDULER_add_select (sched,
727                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
728                                    GNUNET_SCHEDULER_NO_TASK,
729                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
730                                    grs,
731                                    gws,
732                                    &send_execute,
733                                    result);
734   GNUNET_NETWORK_fdset_destroy (gws);
735   GNUNET_NETWORK_fdset_destroy (grs);
736
737   /* FIXME: return bytes REALLY sent */
738   return 0;
739 }
740
741 /**
742  * function to send data to server
743  */
744 static int send_data( struct HTTP_Transfer * result, char * url)
745 {
746
747   curl_handle = curl_easy_init();
748   if( NULL == curl_handle)
749   {
750     printf("easy_init failed \n");
751     return GNUNET_SYSERR;
752   }
753 #if DEBUG_CURL
754   curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
755 #endif
756   curl_easy_setopt(curl_handle, CURLOPT_URL, url);
757   curl_easy_setopt(curl_handle, CURLOPT_PUT, 1L);
758   curl_easy_setopt (curl_handle, CURLOPT_HEADERFUNCTION, &header_function);
759   curl_easy_setopt (curl_handle, CURLOPT_WRITEHEADER, result);
760   curl_easy_setopt (curl_handle, CURLOPT_WRITEFUNCTION, &recv_function);
761   curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, result);
762   curl_easy_setopt (curl_handle, CURLOPT_READFUNCTION, &send_function);
763   curl_easy_setopt (curl_handle, CURLOPT_READDATA, result);
764   curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t) buffer_out.len);
765   curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30);
766   curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 20);
767
768   curl_multi_add_handle(multi_handle, curl_handle);
769
770   send_prepare(result);
771
772   return GNUNET_OK;
773 }
774
775 /**
776  * Plugin notifies transport (aka testcase) about its addresses
777  */
778 void
779 notify_address (void *cls,
780                 const char *name,
781                 const void *addr,
782                 uint16_t addrlen,
783                 struct GNUNET_TIME_Relative expires)
784 {
785   char address[INET6_ADDRSTRLEN];
786   unsigned int port;
787   struct Plugin_Address * pl_addr;
788   struct Plugin_Address * cur;
789
790   if (addrlen == (sizeof (struct IPv4HttpAddress)))
791     {
792       inet_ntop(AF_INET, (struct in_addr *) addr,address,INET_ADDRSTRLEN);
793       port = ntohs(((struct IPv4HttpAddress *) addr)->u_port);
794     }
795   else if (addrlen == (sizeof (struct IPv6HttpAddress)))
796     {
797       inet_ntop(AF_INET6, (struct in6_addr *) addr,address,INET6_ADDRSTRLEN);
798       port = ntohs(((struct IPv6HttpAddress *) addr)->u6_port);
799     }
800   else
801     {
802       GNUNET_break (0);
803       return;
804     }
805   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
806               _("Transport plugin notification for address: `%s':%u\n"),
807               address,
808               port);
809   pl_addr = GNUNET_malloc (sizeof (struct Plugin_Address) );
810   pl_addr->addrlen = addrlen;
811   pl_addr->addr = GNUNET_malloc(addrlen);
812   memcpy(pl_addr->addr,addr,addrlen);
813   pl_addr->next = NULL;
814
815   if ( NULL == addr_head)
816     {
817       addr_head = pl_addr;
818     }
819   else
820     {
821       cur = addr_head;
822       while (NULL != cur->next)
823         {
824           cur = cur->next;
825         }
826       cur->next = pl_addr;
827     }
828   fail_notify_address_count++;
829   fail_notify_address = GNUNET_NO;
830 }
831
832 /**
833  * Setup plugin environment
834  */
835 static void
836 setup_plugin_environment ()
837 {
838   env.cfg = cfg;
839   env.sched = sched;
840   env.stats = stats;
841   env.my_identity = &my_identity;
842   env.cls = &env;
843   env.receive = &receive;
844   env.notify_address = &notify_address;
845   env.max_connections = max_connect_per_transport;
846 }
847
848
849 /**
850  * Task shutting down testcase if it a timeout occurs
851  */
852 static void
853 task_timeout (void *cls,
854             const struct GNUNET_SCHEDULER_TaskContext *tc)
855 {
856   ti_timeout = GNUNET_SCHEDULER_NO_TASK;
857   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
858     return;
859
860   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testcase timeout\n");
861   fail = GNUNET_YES;
862   shutdown_clean();
863   return;
864 }
865
866 static void pretty_printer_cb (void *cls,
867                                const char *address)
868 {
869   if (NULL==address)
870     return;
871   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Plugin returned pretty address: `%s'\n",address);
872   fail_pretty_printer_count++;
873 }
874
875 /**
876  * Runs every single test to test the plugin
877  */
878 static void run_connection_tests( int phase )
879 {
880
881   char * host_str = NULL;
882   /* resetting buffers */
883   buffer_in.size = HTTP_BUFFER_SIZE;
884   buffer_in.pos = 0;
885   buffer_in.len = 0;
886
887   buffer_out.size = HTTP_BUFFER_SIZE;
888   buffer_out.pos = 0;
889   buffer_out.len = 0;
890
891   if (test_no_ident.test_executed == GNUNET_NO)
892   {
893     /* Connecting to peer without identification */
894     char * ident = "";
895     host_str = GNUNET_malloc (strlen ("http:///")+ 1 + strlen (test_addr)+ strlen (ident));
896     GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,ident);
897     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer without any peer identification.\n"));
898     test_no_ident.test_executed = GNUNET_YES;
899     send_data ( &test_no_ident, host_str);
900     GNUNET_free (host_str);
901     return;
902   }
903   if (test_too_short_ident.test_executed == GNUNET_NO)
904   {
905     char * ident = "AAAAAAAAAA";
906     /* Connecting to peer with too short identification */
907     host_str = GNUNET_malloc (strlen ("http:///")+ 1 + strlen (test_addr)+ strlen (ident));
908     GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,ident);
909     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too short peer identification.\n"));
910     test_too_short_ident.test_executed = GNUNET_YES;
911     send_data ( &test_too_short_ident, host_str);
912     GNUNET_free (host_str);
913     return;
914   }
915
916   if (test_too_long_ident.test_executed == GNUNET_NO)
917   {
918     char * ident = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
919
920     /* Connecting to peer with too long identification */
921     host_str = GNUNET_malloc (strlen ("http:///")+ 1 + strlen (test_addr)+ strlen (ident));
922     GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,ident);
923     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too long peer identification.\n"));
924     test_too_long_ident.test_executed = GNUNET_YES;
925     send_data ( &test_too_long_ident, host_str);
926     GNUNET_free (host_str);
927     return;
928   }
929   if (test_valid_ident.test_executed == GNUNET_NO)
930   {
931     struct GNUNET_CRYPTO_HashAsciiEncoded ident;
932     GNUNET_CRYPTO_hash_to_enc(&my_identity.hashPubKey,&ident);
933     host_str = GNUNET_malloc (strlen ("http:///")+ 1 + strlen (test_addr)+ strlen ((char *) &ident));
934     GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,(char *) &ident);
935
936     GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with valid peer identification.\n"));
937     test_valid_ident.test_executed = GNUNET_YES;
938     send_data ( &test_valid_ident, host_str);
939     GNUNET_free (host_str);
940     return;
941   }
942
943   if (phase==1)
944   {
945     /* Using one of the addresses the plugin proposed */
946     GNUNET_assert (addr_head->addr != NULL);
947
948     struct Plugin_Address * tmp_addr;
949     struct GNUNET_MessageHeader msg;
950     char * tmp = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader));
951     char address[INET6_ADDRSTRLEN];
952     unsigned int port;
953     unsigned int type = 10;
954
955     msg.size=htons(sizeof(struct GNUNET_MessageHeader));
956     tmp_addr = addr_head;
957     /* send a message to all addresses advertised by plugin */
958
959     int count = 0;
960     while (tmp_addr != NULL)
961     {
962       if (tmp_addr->addrlen == (sizeof (struct IPv4HttpAddress)))
963         {
964           inet_ntop(AF_INET, (struct in_addr *) tmp_addr->addr,address,INET_ADDRSTRLEN);
965           port = ntohs(((struct IPv4HttpAddress *) tmp_addr->addr)->u_port);
966           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sending message to addres no. %u: `%s':%u\n", count,address, port);
967         }
968       if (tmp_addr->addrlen == (sizeof (struct IPv6HttpAddress)))
969         {
970           inet_ntop(AF_INET6, (struct in6_addr *) tmp_addr->addr,address,INET6_ADDRSTRLEN);
971           port = ntohs(((struct IPv6HttpAddress *) tmp_addr->addr)->u6_port);
972           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sending message to addres no. %u: `%s':%u\n", count,address,port);
973         }
974       msg.type=htons(type);
975       memcpy(tmp,&msg,sizeof(struct GNUNET_MessageHeader));
976       api->send(api->cls, &my_identity, tmp, sizeof(struct GNUNET_MessageHeader), 0, TIMEOUT, NULL,tmp_addr->addr, tmp_addr->addrlen, GNUNET_YES, &task_send_cont, &fail_msgs_transmited_to_local_addrs);
977       tmp_addr = tmp_addr->next;
978       count ++;
979       type ++;
980     }
981     return;
982   }
983
984   if (phase==2)
985   {
986
987     struct GNUNET_MessageHeader msg;
988     char * tmp = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader));
989     /* send a multiple GNUNET_messages at a time*/
990     GNUNET_free(tmp);
991     tmp = GNUNET_malloc(4 * sizeof(struct GNUNET_MessageHeader));
992     struct GNUNET_MessageHeader * msg1 = (struct GNUNET_MessageHeader *) tmp;
993     msg1->size = htons(2 * sizeof(struct GNUNET_MessageHeader));
994     msg1->type = htons(40);
995     struct GNUNET_MessageHeader * msg2 = &msg1[2];
996     msg2->size = htons(2 * sizeof(struct GNUNET_MessageHeader));
997     msg2->type = htons(41);
998     api->send(api->cls, &my_identity, tmp, 4 * sizeof(struct GNUNET_MessageHeader), 0, TIMEOUT, NULL,addr_head->addr, addr_head->addrlen, GNUNET_YES, &task_send_cont, &fail_multiple_msgs_in_transmission);
999
1000     /* send a message with size GNUNET_SERVER_MAX_MESSAGE_SIZE-1  */
1001     GNUNET_free(tmp);
1002     tmp = GNUNET_malloc(GNUNET_SERVER_MAX_MESSAGE_SIZE-1);
1003     uint16_t t = (uint16_t)GNUNET_SERVER_MAX_MESSAGE_SIZE-1;
1004     msg.size = htons(t);
1005     memcpy(tmp,&msg,sizeof(struct GNUNET_MessageHeader));
1006     api->send(api->cls, &my_identity, tmp, GNUNET_SERVER_MAX_MESSAGE_SIZE-1, 0, TIMEOUT, NULL,addr_head->addr, addr_head->addrlen, GNUNET_YES, &task_send_cont, &fail_msg_transmited_max_size);
1007     GNUNET_free(tmp);
1008   }
1009   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No more tests to run\n");
1010 }
1011
1012
1013 /**
1014  * Runs the test.
1015  *
1016  * @param cls closure
1017  * @param s scheduler to use
1018  * @param c configuration to use
1019  */
1020 static void
1021 run (void *cls,
1022      struct GNUNET_SCHEDULER_Handle *s,
1023      char *const *args,
1024      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
1025 {
1026   char * libname;
1027   sched = s;
1028   cfg = c;
1029   char *keyfile;
1030   unsigned long long tneigh;
1031   struct Plugin_Address * cur;
1032   const char * addr_str;
1033
1034
1035   unsigned int suggest_res;
1036
1037   fail_pretty_printer = GNUNET_YES;
1038   fail_notify_address = GNUNET_YES;
1039   fail_addr_to_str = GNUNET_YES;
1040   fail_msgs_transmited_to_local_addrs = 0;
1041   fail_msg_transmited_max_size = GNUNET_YES;
1042   fail_multiple_msgs_in_transmission = 0;
1043
1044   addr_head = NULL;
1045   count_str_addr = 0;
1046   /* parse configuration */
1047   if ((GNUNET_OK !=
1048        GNUNET_CONFIGURATION_get_value_number (c,
1049                                               "TRANSPORT",
1050                                               "NEIGHBOUR_LIMIT",
1051                                               &tneigh)) ||
1052       (GNUNET_OK !=
1053        GNUNET_CONFIGURATION_get_value_filename (c,
1054                                                 "GNUNETD",
1055                                                 "HOSTKEY", &keyfile)))
1056     {
1057       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1058                   _
1059                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
1060       GNUNET_SCHEDULER_shutdown (s);
1061       fail = 1;
1062       return;
1063     }
1064
1065   if ((GNUNET_OK !=
1066       GNUNET_CONFIGURATION_get_value_number (cfg,
1067                                              "transport-http",
1068                                              "PORT",
1069                                              &port)) ||
1070      (port > 65535) || (port == 0))
1071   {
1072     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1073                      "http",
1074                      _
1075                      ("Require valid port number for transport plugin `%s' in configuration!\n"),
1076                      "transport-http");
1077   }
1078
1079   max_connect_per_transport = (uint32_t) tneigh;
1080   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1081   GNUNET_free (keyfile);
1082   if (my_private_key == NULL)
1083     {
1084       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1085                   _("Transport service could not access hostkey.  Exiting.\n"));
1086       GNUNET_SCHEDULER_shutdown (s);
1087       fail = 1;
1088       return;
1089     }
1090
1091   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1092   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &my_identity.hashPubKey);
1093
1094   /* assertions before start */
1095   GNUNET_assert ((port > 0) && (port <= 65535));
1096   GNUNET_assert(&my_public_key != NULL);
1097   GNUNET_assert(&my_identity.hashPubKey != NULL);
1098
1099   /* load plugins... */
1100   setup_plugin_environment ();
1101   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading HTTP transport plugin `%s'\n"),"libgnunet_plugin_transport_http");
1102   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_http");
1103   api = GNUNET_PLUGIN_load (libname, &env);
1104   GNUNET_free (libname);
1105   if (api == NULL)
1106   {
1107     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1108                 _("Failed to load transport plugin for http\n"));
1109     fail = 1;
1110     return;
1111   }
1112
1113   ti_timeout = GNUNET_SCHEDULER_add_delayed (sched, TEST_TIMEOUT, &task_timeout, NULL);
1114
1115   /* testing plugin functionality */
1116   GNUNET_assert (0!=fail_notify_address_count);
1117   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport plugin returned %u addresses to connect to\n"),  fail_notify_address_count);
1118
1119   /* testing pretty printer with all addresses obtained from the plugin*/
1120   cur = addr_head;
1121   while (cur != NULL)
1122   {
1123
1124     api->address_pretty_printer (api->cls, "http",cur->addr,cur->addrlen, GNUNET_NO,TEST_TIMEOUT, &pretty_printer_cb,NULL);
1125     addr_str = api->address_to_string (api->cls, cur->addr, cur->addrlen);
1126     suggest_res = api->check_address (api->cls, cur->addr, cur->addrlen);
1127
1128     GNUNET_assert (GNUNET_OK == suggest_res);
1129     GNUNET_assert (NULL != addr_str);
1130     count_str_addr++;
1131     GNUNET_free ( (char *) addr_str);
1132     cur = cur->next;
1133   }
1134   GNUNET_assert (fail_pretty_printer_count > 0);
1135   GNUNET_assert (fail_pretty_printer_count==fail_notify_address_count);
1136   GNUNET_assert (fail_pretty_printer_count==count_str_addr);
1137   fail_pretty_printer=GNUNET_NO;
1138   fail_addr_to_str=GNUNET_NO;
1139
1140   /* Suggesting addresses with wrong port*/
1141   struct IPv4HttpAddress failing_addr;
1142   failing_addr.ipv4_addr = htonl(INADDR_LOOPBACK);
1143   failing_addr.u_port = htons(0);
1144   suggest_res = api->check_address (api->cls,&failing_addr,sizeof (struct IPv4HttpAddress));
1145   GNUNET_assert (GNUNET_SYSERR == suggest_res);
1146
1147   /* Suggesting addresses with wrong size*/
1148   failing_addr.ipv4_addr = htonl(INADDR_LOOPBACK);
1149   failing_addr.u_port = htons(0);
1150   suggest_res = api->check_address (api->cls,&failing_addr,sizeof (struct IPv6HttpAddress));
1151   GNUNET_assert (GNUNET_SYSERR == suggest_res);
1152
1153   /* Suggesting addresses with wrong address*/
1154   failing_addr.ipv4_addr = htonl(INADDR_LOOPBACK);
1155   failing_addr.u_port = htons(12389);
1156   suggest_res = api->check_address (api->cls,&failing_addr,sizeof (struct IPv4HttpAddress));
1157   GNUNET_assert (GNUNET_SYSERR == suggest_res);
1158
1159   /* test sending to client */
1160   multi_handle = curl_multi_init();
1161
1162   /* Setting up buffers */
1163   buffer_in.size = HTTP_BUFFER_SIZE;
1164   buffer_in.pos = 0;
1165   buffer_in.len = 0;
1166
1167   buffer_out.size = HTTP_BUFFER_SIZE;
1168   buffer_out.pos = 0;
1169   buffer_out.len = 0;
1170
1171   /* Setting up connection tests */
1172
1173   /* Test: connecting without a peer identification */
1174   test_no_ident.test_executed = GNUNET_NO;
1175   test_no_ident.test_failed = GNUNET_YES;
1176
1177   /* Test: connecting with too short peer identification */
1178   test_too_short_ident.test_executed = GNUNET_NO;
1179   test_too_short_ident.test_failed = GNUNET_YES;
1180
1181   /* Test: connecting with too long peer identification */
1182   test_too_long_ident.test_executed = GNUNET_NO;
1183   test_too_long_ident.test_failed = GNUNET_YES;
1184
1185   /* Test: connecting with valid identification */
1186   test_valid_ident.test_executed = GNUNET_NO;
1187   test_valid_ident.test_failed = GNUNET_YES;
1188
1189   test_addr = (char *) api->address_to_string (api->cls,addr_head->addr,addr_head->addrlen);
1190   run_connection_tests(0);
1191
1192   /* testing finished */
1193
1194   return;
1195 }
1196
1197
1198 /**
1199  * The main function for the transport service.
1200  *
1201  * @param argc number of arguments from the command line
1202  * @param argv command line arguments
1203  * @return 0 ok, 1 on error
1204  */
1205 int
1206 main (int argc, char *const *argv)
1207 {
1208
1209   static struct GNUNET_GETOPT_CommandLineOption options[] = {
1210     GNUNET_GETOPT_OPTION_END
1211   };
1212   int ret;
1213   char *const argv_prog[] = {
1214     "test_plugin_transport_http",
1215     "-c",
1216     "test_plugin_transport_data_http.conf",
1217     "-L",
1218 #if VERBOSE
1219     "DEBUG",
1220 #else
1221     "WARNING",
1222 #endif
1223     NULL
1224   };
1225   GNUNET_log_setup ("test_plugin_transport_http",
1226 #if VERBOSE
1227                     "DEBUG",
1228 #else
1229                     "WARNING",
1230 #endif
1231                     NULL);
1232
1233   ret = (GNUNET_OK ==
1234          GNUNET_PROGRAM_run (5,
1235                              argv_prog,
1236                              "test_plugin_transport_http",
1237                              "testcase", options, &run, NULL)) ? GNUNET_NO : GNUNET_YES;
1238
1239     GNUNET_DISK_directory_remove ("/tmp/test_plugin_transport_http");
1240
1241   return fail;
1242 }
1243
1244 /* end of test_plugin_transport_http.c */