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