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