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