(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_getopt_lib.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_plugin_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_program_lib.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_service_lib.h"
37 #include "plugin_transport.h"
38 #include "gnunet_statistics_service.h"
39 #include "transport.h"
40 #include <curl/curl.h>
41
42 #define VERBOSE GNUNET_YES
43 #define DEBUG GNUNET_YES
44
45 #define PLUGIN libgnunet_plugin_transport_template
46
47 /**
48  * How long until we give up on transmitting the message?
49  */
50 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
51
52 /**
53  * How long until we give up on transmitting the message?
54  */
55 #define STAT_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
56
57 /**
58  * Our public key.
59  */
60 /* static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; */
61
62 /**
63  * Our public key.
64  */
65 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
66
67 /**
68  * Our identity.
69  */
70 static struct GNUNET_PeerIdentity my_identity;
71
72 /**
73  * Our private key.
74  */
75 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
76
77
78 /**
79  * Our scheduler.
80  */
81 struct GNUNET_SCHEDULER_Handle *sched;
82
83 /**
84  * Our statistics handle.
85  */
86 struct GNUNET_STATISTICS_Handle *stats;
87
88
89 /**
90  * Our configuration.
91  */
92 const struct GNUNET_CONFIGURATION_Handle *cfg;
93
94 /**
95  * Number of neighbours we'd like to have.
96  */
97 static uint32_t max_connect_per_transport;
98
99 /**
100  * Environment for this plugin.
101  */
102 static struct GNUNET_TRANSPORT_PluginEnvironment env;
103
104 /**
105  *handle for the api provided by this plugin
106  */
107 static struct GNUNET_TRANSPORT_PluginFunctions *api;
108
109 /**
110  * ID of the task controlling the testcase timeout
111  */
112 static GNUNET_SCHEDULER_TaskIdentifier ti_timeout;
113
114
115 static GNUNET_SCHEDULER_TaskIdentifier ti_send;
116
117 static unsigned int timeout_count;
118 static unsigned int recieved;
119 const struct GNUNET_PeerIdentity * p;
120
121 /**
122  * Did the test pass or fail?
123  */
124 static int fail;
125
126 //static int done;
127
128 pid_t pid;
129
130 static void
131 task_send (void *cls,
132             const struct GNUNET_SCHEDULER_TaskContext *tc)
133 {
134   ti_timeout = GNUNET_SCHEDULER_NO_TASK;
135   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
136     return;
137
138   struct GNUNET_MessageHeader * msg = cls;
139   unsigned int len = ntohs(msg->size);
140   const char * msgc = (const char *) msg;
141
142   api->send(api->cls,p,msgc, len, 0, TIMEOUT, NULL,NULL, 0, GNUNET_NO, NULL, NULL);
143
144 }
145
146 /**
147  * Initialize Environment for this plugin
148  */
149 static struct GNUNET_TIME_Relative
150 receive (void *cls,
151          const struct GNUNET_PeerIdentity * peer,
152          const struct GNUNET_MessageHeader * message,
153          uint32_t distance,
154          struct Session *session,
155          const char *sender_address,
156          uint16_t sender_address_len)
157 {
158   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));
159
160
161
162   recieved = GNUNET_YES;
163   p = peer;
164   void * c = (void *) message;
165
166   ti_send =GNUNET_SCHEDULER_add_delayed (sched, STAT_INTERVALL, &task_send, c);
167   return GNUNET_TIME_UNIT_ZERO;
168 }
169
170 void
171 notify_address (void *cls,
172                 const char *name,
173                 const void *addr,
174                 uint16_t addrlen,
175                 struct GNUNET_TIME_Relative expires)
176 {
177
178 }
179
180 /**
181  * Simple example test that invokes
182  * the check_address function of the plugin.
183  */
184 /* FIXME: won't work on IPv6 enabled systems where IPv4 mapping
185  * isn't enabled (eg. FreeBSD > 4)[TESTING]
186 WEAKRANDOM = YES
187  */
188 static void
189 shutdown_clean ()
190 {
191 /*  if (stat_get_handle != NULL)
192   {
193     GNUNET_STATISTICS_get_cancel(stat_get_handle);
194   }*/
195
196   /* if ( NULL!=stats )GNUNET_STATISTICS_destroy (stats, GNUNET_YES); */
197   if (ti_timeout != GNUNET_SCHEDULER_NO_TASK)
198     GNUNET_SCHEDULER_cancel(sched,ti_timeout);
199   ti_timeout = GNUNET_SCHEDULER_NO_TASK;
200
201   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unloading http plugin\n");
202   GNUNET_assert (NULL == GNUNET_PLUGIN_unload ("libgnunet_plugin_transport_http", api));
203   
204   GNUNET_SCHEDULER_shutdown(sched);
205   /* FIXME: */ fail = GNUNET_NO;
206   return;
207 }
208
209 static void
210 setup_plugin_environment ()
211 {
212   env.cfg = cfg;
213   env.sched = sched;
214   env.stats = stats;
215   env.my_identity = &my_identity;
216   env.cls = &env;
217   env.receive = &receive;
218   env.notify_address = &notify_address;
219   env.max_connections = max_connect_per_transport;
220 }
221
222 #if 0
223 static int
224 process_stat (void *cls,
225               const char *subsystem,
226               const char *name,
227               uint64_t value,
228               int is_persistent)
229 {
230   stat_get_handle = NULL;
231   if (value==1)
232     {
233     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown, plugin failed \n");
234     fail = GNUNET_YES;
235     shutdown_clean();
236     return GNUNET_YES;
237     }
238   if (value==2)
239     {
240     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown, plugin not failed \n");
241     shutdown_clean();
242     return GNUNET_YES;
243     }
244   return GNUNET_YES;
245 }
246 #endif
247
248 #if 0
249 static void
250 cont_func (void *cls, int success)
251 {
252   stat_get_handle = NULL;
253 }
254 #endif
255
256
257
258 /**
259  * Task that checks if we should try to download a hostlist.
260  * If so, we initiate the download, otherwise we schedule
261  * this task again for a later time.
262  */
263 static void
264 task_timeout (void *cls,
265             const struct GNUNET_SCHEDULER_TaskContext *tc)
266 {
267   ti_timeout = GNUNET_SCHEDULER_NO_TASK;
268   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
269     return;
270
271   if ( timeout_count > 1 )
272   {
273     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testcase timeout\n",  timeout_count);
274     fail = GNUNET_YES;
275     shutdown_clean();
276     return;
277   }
278   timeout_count++;
279
280 /*  stat_get_handle = GNUNET_STATISTICS_get (stats,
281                                            "http-transport",
282                                            gettext_noop("shutdown"),
283                                            GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
284                                            &cont_func,
285                                            &process_stat,
286                                            NULL);*/
287
288   ti_timeout = GNUNET_SCHEDULER_add_delayed (sched, STAT_INTERVALL, &task_timeout, NULL);
289   return;
290 }
291
292 #if 0
293 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
294 {
295   size_t retcode;
296
297   /* in real-world cases, this would probably get this data differently
298      as this fread() stuff is exactly what the library already would do
299      by default internally */
300   retcode = fread(ptr, size, nmemb, stream);
301
302   fprintf(stderr, "*** We read %d bytes from file\n", (int) retcode);
303
304   return retcode;
305 }
306 #endif
307
308 struct CBC
309 {
310   char *buf;
311   size_t pos;
312   size_t size;
313 };
314
315 #if 0
316 static size_t
317 putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
318 {
319   size_t len;
320
321   struct CBC  * cbc = ptr;
322
323   len = strlen(cbc->buf);
324
325   if (( cbc->pos == len) && (len < (size * nmemb)))
326     return 0;
327   memcpy(stream, cbc->buf, len+1);
328   cbc->pos = len;
329   return len;
330 }
331 #endif
332
333 #if 0
334 static int execute (char * url)
335 {
336   done = 0;
337   CURLM *multi_handle;
338   CURL *curl_handle;
339   CURLMsg *msg;
340   int msgs_left;
341   FILE * hd_src ;
342   int hd ;
343   struct stat file_info;
344   int still_running;
345   char buf[2048];
346   struct CBC cbc;
347
348   char *file = "curl.c";
349
350   cbc.buf = buf;
351   cbc.size = 2048;
352   cbc.pos = 0;
353
354   const char * txt = "Hello World!";
355   memcpy(cbc.buf,txt,strlen(txt)+1);
356   //fprintf(stderr,"%s %u\n",src,strlen(src));
357
358   /* get the file size of the local file */
359   hd = open(file, O_RDONLY) ;
360   fstat(hd, &file_info);
361   close(hd) ;
362
363   /* get a FILE * of the same file, could also be made with
364      fdopen() from the previous descriptor, but hey this is just
365      an example! */
366   hd_src = fopen(file, "rb");
367   //printf("size: %u \n", (curl_off_t) file_info.st_size);
368
369   /* get a curl handle */
370   curl_handle = curl_easy_init();
371   if( NULL == curl_handle)
372   {
373     printf("easy_init failed \n");
374     return 0;
375   }
376   curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
377   //curl_easy_setopt (curl_handle, CURLOPT_WRITEFUNCTION, &copyBuffer);
378   //curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, &cbc);
379   curl_easy_setopt (curl_handle, CURLOPT_READFUNCTION, &putBuffer);
380   curl_easy_setopt (curl_handle, CURLOPT_READDATA, &cbc);
381   curl_easy_setopt(curl_handle, CURLOPT_UPLOAD, 1L);
382   curl_easy_setopt(curl_handle, CURLOPT_PUT, 1L);
383   curl_easy_setopt(curl_handle, CURLOPT_URL, url);
384   curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t) strlen(txt));
385
386   //curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
387
388   multi_handle = curl_multi_init();
389   curl_multi_add_handle(multi_handle, curl_handle);
390
391   while(CURLM_CALL_MULTI_PERFORM ==
392         curl_multi_perform(multi_handle, &still_running));
393
394   while(still_running)
395   {
396       struct timeval timeout;
397       int rc; /* select() return code */
398
399       fd_set fdread;
400       fd_set fdwrite;
401       fd_set fdexcep;
402       int maxfd = -1;
403
404       FD_ZERO(&fdread);
405       FD_ZERO(&fdwrite);
406       FD_ZERO(&fdexcep);
407
408       /* set a suitable timeout to play around with */
409       timeout.tv_sec = 1;
410       timeout.tv_usec = 0;
411
412       /* get file descriptors from the transfers */
413       curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
414
415       /* In a real-world program you OF COURSE check the return code of the
416          function calls.  On success, the value of maxfd is guaranteed to be
417          greater or equal than -1.  We call select(maxfd + 1, ...), specially in
418          case of (maxfd == -1), we call select(0, ...), which is basically equal
419          to sleep. */
420
421       rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
422
423       switch(rc)
424       {
425       case -1:
426         /* select error */
427         break;
428       case 0:
429         /* timeout, do something else */
430         break;
431       default:
432         /* one or more of curl's file descriptors say there's data to read
433            or write */
434         while(CURLM_CALL_MULTI_PERFORM ==
435               curl_multi_perform(multi_handle, &still_running));
436         break;
437       }
438   }
439
440   /* See how the transfers went */
441   while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
442     if (msg->msg == CURLMSG_DONE) {
443       int idx, found = 0;
444
445       /* Find out which handle this message is about */
446       for (idx=0; idx<1; idx++) {
447         found = (msg->easy_handle == curl_handle);
448         if(found)
449           break;
450       }
451
452       switch (idx) {
453       case 0:
454         printf("HTTP transfer completed with status %d\n", msg->data.result);
455         break;
456       }
457     }
458   }
459
460   curl_multi_cleanup(multi_handle);
461
462   curl_easy_cleanup(curl_handle);
463
464   fclose(hd_src); /* close the local file */
465   return 0;
466 }
467 #endif
468
469 #if 0
470 /**
471  * Task that checks if we should try to download a hostlist.
472  * If so, we initiate the download, otherwise we schedule
473  * this task again for a later time.
474  */
475 static void
476 task_download (void *cls,
477             const struct GNUNET_SCHEDULER_TaskContext *tc)
478 {
479   ti_download = GNUNET_SCHEDULER_NO_TASK;
480   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
481     return;
482
483   execute ("http://localhost:12389/Q7BO0ELEHAT8JNENQ90112G0TACH2H2HIR4IJ2JQ28U6FV14CK44EVP26FVAEALO7HIRJFLFE6709RP6IITM64B0FU7J4RA8KPNDKN8");
484
485   return;
486 }
487 #endif
488
489 /**
490  * Runs the test.
491  *
492  * @param cls closure
493  * @param s scheduler to use
494  * @param c configuration to use
495  */
496 static void
497 run (void *cls,
498      struct GNUNET_SCHEDULER_Handle *s,
499      char *const *args,
500      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
501 {
502   char * libname;
503   sched = s;
504   cfg = c;
505   char *keyfile;
506   unsigned long long tneigh;
507
508   /* settings up statistics */
509 /*  stats = GNUNET_STATISTICS_create (sched, "http-transport", cfg);
510   if (NULL == stats)
511   {
512     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
513                 _("Failed to retrieve statistics handle\n"));
514     fail = GNUNET_YES;
515     shutdown_clean();
516     return ;
517   }*/
518
519   /* parse configuration */
520   if ((GNUNET_OK !=
521        GNUNET_CONFIGURATION_get_value_number (c,
522                                               "TRANSPORT",
523                                               "NEIGHBOUR_LIMIT",
524                                               &tneigh)) ||
525       (GNUNET_OK !=
526        GNUNET_CONFIGURATION_get_value_filename (c,
527                                                 "GNUNETD",
528                                                 "HOSTKEY", &keyfile)))
529     {
530       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
531                   _
532                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
533       GNUNET_SCHEDULER_shutdown (s);
534       return;
535     }
536   max_connect_per_transport = (uint32_t) tneigh;
537   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
538   GNUNET_free (keyfile);
539   if (my_private_key == NULL)
540     {
541       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
542                   _
543                   ("Transport service could not access hostkey.  Exiting.\n"));
544       GNUNET_SCHEDULER_shutdown (s);
545       return;
546     }
547   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
548   GNUNET_CRYPTO_hash (&my_public_key,
549                       sizeof (my_public_key), &my_identity.hashPubKey);
550
551   /* load plugins... */
552   setup_plugin_environment ();
553   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading HTTP transport plugin `%s'\n"),"libgnunet_plugin_transport_http");
554   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_http");
555   api = GNUNET_PLUGIN_load (libname, &env);
556   GNUNET_free (libname);
557   if (api == NULL)
558   {
559     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
560                 _("Failed to load transport plugin for http\n"));
561     fail = GNUNET_YES;
562     return;
563   }
564
565   ti_timeout = GNUNET_SCHEDULER_add_delayed (sched, STAT_INTERVALL, &task_timeout, NULL);
566   //ti_download = GNUNET_SCHEDULER_add_now (sched, &task_download, NULL);
567
568   return;
569
570 }
571
572
573 /**
574  * The main function for the transport service.
575  *
576  * @param argc number of arguments from the command line
577  * @param argv command line arguments
578  * @return 0 ok, 1 on error
579  */
580 int
581 main (int argc, char *const *argv)
582 {
583
584   static struct GNUNET_GETOPT_CommandLineOption options[] = {
585     GNUNET_GETOPT_OPTION_END
586   };
587   int ret;
588   char *const argv_prog[] = {
589     "test_plugin_transport_http",
590     "-c",
591     "test_plugin_transport_data_http.conf",
592     "-L",
593 #if VERBOSE
594     "DEBUG",
595 #else
596     "WARNING",
597 #endif
598     NULL
599   };
600   GNUNET_log_setup ("test_plugin_transport_http",
601 #if VERBOSE
602                     "DEBUG",
603 #else
604                     "WARNING",
605 #endif
606                     NULL);
607 /*  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Starting statistics service\n");
608   pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-statistics",
609                                  "gnunet-service-statistics",
610                                  "-L", "DEBUG",
611                                  "-c", "test_plugin_transport_data_http.conf", NULL);
612
613   fail = GNUNET_NO;
614   if (pid==-1 )
615   {
616     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failed to start statistics service\n");
617     fail = GNUNET_YES;
618     return fail;
619   }*/
620
621   ret = (GNUNET_OK ==
622          GNUNET_PROGRAM_run (5,
623                              argv_prog,
624                              "test_plugin_transport_http",
625                              "testcase", options, &run, NULL)) ? GNUNET_NO : GNUNET_YES;
626
627     GNUNET_DISK_directory_remove ("/tmp/test_plugin_transport_http");
628
629
630 /*  if (0 != PLIBC_KILL (pid, SIGTERM))
631   {
632     GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "Failed to kill statistics service");
633     fail = GNUNET_YES;
634   }
635   if (GNUNET_OS_process_wait(pid) != GNUNET_OK)
636     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
637   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Killed statistics service\n");*/
638   return fail;
639 }
640
641 /* end of test_plugin_transport_http.c */