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