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