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