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