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