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