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