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