(no commit message)
[oweals/gnunet.git] / src / transport / plugin_transport_http.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 /**
22  * @file transport/plugin_transport_template.c
23  * @brief template for a new transport service
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_connection_lib.h"
31 #include "gnunet_server_lib.h"
32 #include "gnunet_service_lib.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_resolver_service.h"
36 #include "plugin_transport.h"
37 #include "gnunet_os_lib.h"
38 #include "microhttpd.h"
39 #include <curl/curl.h>
40
41
42 #define DEBUG_CURL GNUNET_CURL
43 #define DEBUG_HTTP GNUNET_NO
44
45 /**
46  * Text of the response sent back after the last bytes of a PUT
47  * request have been received (just to formally obey the HTTP
48  * protocol).
49  */
50 #define HTTP_PUT_RESPONSE "Thank you!"
51
52 /**
53  * After how long do we expire an address that we
54  * learned from another peer if it is not reconfirmed
55  * by anyone?
56  */
57 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
58
59 /**
60  * Page returned if request invalid
61  */
62 #define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
63
64 /**
65  * Timeout for a http connect
66  */
67 #define HTTP_CONNECT_TIMEOUT 30
68
69 /**
70  * Timeout for a http connect
71  */
72 #define HTTP_MESSAGE_INITIAL_BUFFERSIZE GNUNET_SERVER_MAX_MESSAGE_SIZE
73
74
75 /**
76  * Encapsulation of all of the state of the plugin.
77  */
78 struct Plugin;
79
80 /**
81  * Network format for IPv4 addresses.
82  */
83 struct IPv4HttpAddress
84 {
85   /**
86    * IPv4 address, in network byte order.
87    */
88   uint32_t ipv4_addr;
89
90   /**
91    * Port number, in network byte order.
92    */
93   uint16_t u_port;
94
95 };
96
97
98 /**
99  * Network format for IPv6 addresses.
100  */
101 struct IPv6HttpAddress
102 {
103   /**
104    * IPv6 address.
105    */
106   struct in6_addr ipv6_addr;
107
108   /**
109    * Port number, in network byte order.
110    */
111   uint16_t u6_port;
112
113 };
114
115
116
117 /**
118  *  Message to send using http
119  */
120 struct HTTP_Message
121 {
122   /**
123    * Next field for linked list
124    */
125   struct HTTP_Message * next;
126
127   /**
128    * buffer containing data to send
129    */
130   char *buf;
131
132   /**
133    * amount of data already sent
134    */
135   size_t pos;
136
137   /**
138    * amount of data to sent
139    */
140   size_t len;
141 };
142
143
144 /**
145  * Session handle for connections.
146  */
147 struct Session
148 {
149
150   /**
151    * Stored in a linked list.
152    */
153   struct Session *next;
154
155   /**
156    * Pointer to the global plugin struct.
157    */
158   struct Plugin *plugin;
159
160   /**
161    * Continuation function to call once the transmission buffer
162    * has again space available.  NULL if there is no
163    * continuation to call.
164    */
165   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
166
167   /**
168    * Closure for transmit_cont.
169    */
170   void *transmit_cont_cls;
171
172   /**
173    * To whom are we talking to (set to our identity
174    * if we are still waiting for the welcome message)
175    */
176   struct GNUNET_PeerIdentity sender;
177
178   /**
179    * Sender's url
180    */
181   char * url;
182
183   /**
184    * Sender's ip address to distinguish between incoming connections
185    */
186   char * ip;
187
188   /**
189    * Sender's ip address to distinguish between incoming connections
190    */
191   struct sockaddr_in * addr;
192
193   /**
194    * Did we initiate the connection (GNUNET_YES) or the other peer (GNUNET_NO)?
195    */
196   unsigned int is_client;
197
198   /**
199    * Is the connection active (GNUNET_YES) or terminated (GNUNET_NO)?
200    */
201   unsigned int is_active;
202
203   /**
204    * At what time did we reset last_received last?
205    */
206   struct GNUNET_TIME_Absolute last_quota_update;
207
208   /**
209    * How many bytes have we received since the "last_quota_update"
210    * timestamp?
211    */
212   uint64_t last_received;
213
214   /**
215    * Number of bytes per ms that this peer is allowed
216    * to send to us.
217    */
218   uint32_t quota;
219
220   /**
221    * Is there a HTTP/PUT in progress?
222    */
223   unsigned int is_put_in_progress;
224
225   /**
226    * Is there a HTTP/PUT in progress?
227    */
228   unsigned int is_bad_request;
229
230   /**
231    * Encoded hash
232    */
233   struct GNUNET_CRYPTO_HashAsciiEncoded hash;
234
235   struct HTTP_Message * pending_outbound_msg;;
236
237   struct HTTP_Message * pending_inbound_msg;
238
239   CURL *curl_handle;
240 };
241
242 /**
243  * Encapsulation of all of the state of the plugin.
244  */
245 struct Plugin
246 {
247   /**
248    * Our environment.
249    */
250   struct GNUNET_TRANSPORT_PluginEnvironment *env;
251
252   /**
253    * Handle to the network service.
254    */
255   struct GNUNET_SERVICE_Context *service;
256
257   unsigned int port_inbound;
258
259   /**
260    * List of open sessions.
261    */
262   struct Session *sessions;
263
264   /**
265    * Number of active sessions
266    */
267
268   unsigned int session_count;
269 };
270
271 /**
272  * Daemon for listening for new IPv4 connections.
273  */
274 static struct MHD_Daemon *http_daemon_v4;
275
276 /**
277  * Daemon for listening for new IPv6connections.
278  */
279 static struct MHD_Daemon *http_daemon_v6;
280
281 /**
282  * Our primary task for http daemon handling IPv4 connections
283  */
284 static GNUNET_SCHEDULER_TaskIdentifier http_task_v4;
285
286 /**
287  * Our primary task for http daemon handling IPv6 connections
288  */
289 static GNUNET_SCHEDULER_TaskIdentifier http_task_v6;
290
291
292 /**
293  * The task sending data
294  */
295 static GNUNET_SCHEDULER_TaskIdentifier http_task_send;
296
297
298 /**
299  * Information about this plugin
300  */
301 static struct Plugin *plugin;
302
303 /**
304  * cURL Multihandle
305  */
306 static CURLM *multi_handle;
307
308 /**
309  * Our hostname
310  */
311 static char * hostname;
312
313 /**
314  * Our ASCII encoded, hashed peer identity
315  * This string is used to distinguish between connections and is added to the urls
316  */
317 static struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
318
319 struct GNUNET_TIME_Relative timeout;
320
321 /**
322  * Finds a http session in our linked list using peer identity as a key
323  * @param peer peeridentity
324  * @return http session corresponding to peer identity
325  */
326 static struct Session * find_session_by_pi( const struct GNUNET_PeerIdentity *peer )
327 {
328   struct Session * cur;
329   GNUNET_HashCode hc_peer;
330   GNUNET_HashCode hc_current;
331
332   cur = plugin->sessions;
333   hc_peer = peer->hashPubKey;
334   while (cur != NULL)
335   {
336     hc_current = cur->sender.hashPubKey;
337     if ( 0 == GNUNET_CRYPTO_hash_cmp( &hc_peer, &hc_current))
338       return cur;
339     cur = plugin->sessions->next;
340   }
341   return NULL;
342 }
343
344 /**
345  * Finds a http session in our linked list using libcurl handle as a key
346  * Needed when sending data with libcurl to differentiate between sessions
347  * @param handle peeridentity
348  * @return http session corresponding to peer identity
349  */
350 static struct Session * find_session_by_curlhandle( CURL* handle )
351 {
352   struct Session * cur;
353
354   cur = plugin->sessions;
355   while (cur != NULL)
356   {
357     if ( handle == cur->curl_handle )
358       return cur;
359     cur = plugin->sessions->next;
360   }
361   return NULL;
362 }
363
364 /**
365  * Create a new session
366  *
367  * @param address address the peer is using
368  * @param peer identity
369  * @return created session object
370  */
371 static struct Session * create_session (struct sockaddr_in *address, const struct GNUNET_PeerIdentity *peer)
372 {
373   struct sockaddr_in  *addrin;
374   struct sockaddr_in6 *addrin6;
375
376   struct Session * ses = GNUNET_malloc ( sizeof( struct Session) );
377   ses->addr = GNUNET_malloc ( sizeof (struct sockaddr_in) );
378
379   ses->next = NULL;
380   ses->plugin = plugin;
381
382   memcpy(ses->addr, address, sizeof (struct sockaddr_in));
383   if ( AF_INET == address->sin_family)
384   {
385     ses->ip = GNUNET_malloc (INET_ADDRSTRLEN);
386     addrin = address;
387     inet_ntop(addrin->sin_family,&(addrin->sin_addr),ses->ip,INET_ADDRSTRLEN);
388   }
389   if ( AF_INET6 == address->sin_family)
390   {
391     ses->ip = GNUNET_malloc (INET6_ADDRSTRLEN);
392     addrin6 = (struct sockaddr_in6 *) address;
393     inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr) ,ses->ip,INET6_ADDRSTRLEN);
394   }
395   memcpy(&ses->sender, peer, sizeof (struct GNUNET_PeerIdentity));
396   GNUNET_CRYPTO_hash_to_enc(&ses->sender.hashPubKey,&(ses->hash));
397   ses->is_active = GNUNET_NO;
398   ses->pending_inbound_msg = GNUNET_malloc( sizeof (struct HTTP_Message));
399   ses->pending_inbound_msg->buf = GNUNET_malloc(GNUNET_SERVER_MAX_MESSAGE_SIZE);
400   ses->pending_inbound_msg->len = GNUNET_SERVER_MAX_MESSAGE_SIZE;
401   ses->pending_inbound_msg->pos = 0;
402
403
404   return ses;
405 }
406
407 /**
408  * Callback called by MHD when a connection is terminated
409  */
410 static void requestCompletedCallback (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
411 {
412   struct Session * cs;
413
414   cs = *httpSessionCache;
415   if (cs != NULL)
416   {
417     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection from peer `%s' was terminated\n",GNUNET_i2s(&cs->sender));
418     /* session set to inactive */
419     cs->is_active = GNUNET_NO;
420     cs->is_put_in_progress = GNUNET_NO;
421   }
422   return;
423 }
424
425 /**
426  * Check if we are allowed to connect to the given IP.
427  */
428 static int
429 acceptPolicyCallback (void *cls,
430                       const struct sockaddr *addr, socklen_t addr_len)
431 {
432   /* Every connection is accepted, nothing more to do here */
433   return MHD_YES;
434 }
435
436
437 int serror;
438
439 /**
440  * Process GET or PUT request received via MHD.  For
441  * GET, queue response that will send back our pending
442  * messages.  For PUT, process incoming data and send
443  * to GNUnet core.  In either case, check if a session
444  * already exists and create a new one if not.
445  */
446 static int
447 accessHandlerCallback (void *cls,
448                        struct MHD_Connection *session,
449                        const char *url,
450                        const char *method,
451                        const char *version,
452                        const char *upload_data,
453                        size_t * upload_data_size, void **httpSessionCache)
454 {
455   struct MHD_Response *response;
456   struct Session * cs;
457   struct Session * cs_temp;
458   const union MHD_ConnectionInfo * conn_info;
459   struct sockaddr_in  *addrin;
460   struct sockaddr_in6 *addrin6;
461   char * address = NULL;
462   struct GNUNET_PeerIdentity pi_in;
463   int res = GNUNET_NO;
464   struct GNUNET_MessageHeader *gn_msg;
465   int send_error_to_client;
466
467   gn_msg = NULL;
468   send_error_to_client = GNUNET_NO;
469
470   if ( NULL == *httpSessionCache)
471   {
472     /* check url for peer identity */
473     res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
474     if ( GNUNET_SYSERR == res )
475     {
476       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident\n");
477       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
478       res = MHD_queue_response (session, MHD_HTTP_NOT_FOUND, response);
479       MHD_destroy_response (response);
480       return res;
481     }
482
483     conn_info = MHD_get_connection_info(session, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
484     /* Incoming IPv4 connection */
485     if ( AF_INET == conn_info->client_addr->sin_family)
486     {
487       address = GNUNET_malloc (INET_ADDRSTRLEN);
488       addrin = conn_info->client_addr;
489       inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
490     }
491     /* Incoming IPv6 connection */
492     if ( AF_INET6 == conn_info->client_addr->sin_family)
493     {
494       address = GNUNET_malloc (INET6_ADDRSTRLEN);
495       addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
496       inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
497     }
498     /* find existing session for address */
499     cs = NULL;
500     if (plugin->session_count > 0)
501     {
502       cs = plugin->sessions;
503       while ( NULL != cs)
504       {
505
506         /* Comparison based on ip address */
507         // res = (0 == memcmp(&(conn_info->client_addr->sin_addr),&(cs->addr->sin_addr), sizeof (struct in_addr))) ? GNUNET_YES : GNUNET_NO;
508
509         /* Comparison based on ip address, port number and address family */
510         // res = (0 == memcmp((conn_info->client_addr),(cs->addr), sizeof (struct sockaddr_in))) ? GNUNET_YES : GNUNET_NO;
511
512         /* Comparison based on PeerIdentity */
513         res = (0 == memcmp(&pi_in,&(cs->sender), sizeof (struct GNUNET_PeerIdentity))) ? GNUNET_YES : GNUNET_NO;
514
515         if ( GNUNET_YES  == res)
516         {
517           /* existing session for this address found */
518           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session `%s' found\n",address);
519           break;
520         }
521         cs = cs->next;
522       }
523     }
524     /* no existing session, create a new one*/
525     if (cs == NULL )
526     {
527       /* create new session object */
528       cs = create_session(conn_info->client_addr, &pi_in);
529
530       /* Insert session into linked list */
531       if ( plugin->sessions == NULL)
532       {
533         plugin->sessions = cs;
534         plugin->session_count = 1;
535       }
536       cs_temp = plugin->sessions;
537       while ( cs_temp->next != NULL )
538       {
539         cs_temp = cs_temp->next;
540       }
541       if (cs_temp != cs )
542       {
543         cs_temp->next = cs;
544         plugin->session_count++;
545       }
546       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"New Session `%s' inserted, count %u \n", address, plugin->session_count);
547     }
548     /* Set closure */
549     if (*httpSessionCache == NULL)
550     {
551       *httpSessionCache = cs;
552     }
553     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has new an incoming `%s' request from peer `%s' (`[%s]:%u')\n",method, GNUNET_i2s(&cs->sender),cs->ip,cs->addr->sin_port);
554   }
555   else
556   {
557     cs = *httpSessionCache;
558   }
559   /* Is it a PUT or a GET request */
560   if ( 0 == strcmp (MHD_HTTP_METHOD_PUT, method) )
561   {
562     /* New  */
563     if ((*upload_data_size == 0) && (cs->is_put_in_progress == GNUNET_NO))
564     {
565       if (cs->pending_inbound_msg->pos !=0 )
566       {
567         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
568                     _("Incoming message from peer `%s', while existing message with %u bytes was not forwarded to transport'\n"),
569                     GNUNET_i2s(&cs->sender), cs->pending_inbound_msg->pos);
570         cs->pending_inbound_msg->pos = 0;
571       }
572       /* not yet ready */
573       cs->is_put_in_progress = GNUNET_YES;
574       cs->is_bad_request = GNUNET_NO;
575       cs->is_active = GNUNET_YES;
576       return MHD_YES;
577     }
578
579     if ((*upload_data_size > 0) && (cs->is_bad_request != GNUNET_YES))
580     {
581       if ((*upload_data_size + cs->pending_inbound_msg->pos < cs->pending_inbound_msg->len) && (*upload_data_size + cs->pending_inbound_msg->pos <= GNUNET_SERVER_MAX_MESSAGE_SIZE))
582       {
583         /* copy uploaded data to buffer */
584         memcpy(&cs->pending_inbound_msg->buf[cs->pending_inbound_msg->pos],upload_data,*upload_data_size);
585         cs->pending_inbound_msg->pos += *upload_data_size;
586         *upload_data_size = 0;
587         return MHD_YES;
588       }
589       else
590       {
591         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"%u bytes not added to message of %u bytes, message to big\n",*upload_data_size, cs->pending_inbound_msg->pos);
592         cs->is_bad_request = GNUNET_YES;
593         /* (*upload_data_size) bytes not processed */
594         return MHD_YES;
595       }
596     }
597
598     if ((cs->is_put_in_progress == GNUNET_YES) && (cs->is_bad_request == GNUNET_YES))
599     {
600       *upload_data_size = 0;
601       response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
602       res = MHD_queue_response (session, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, response);
603       if (res == MHD_YES)
604       {
605         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 413 ENTITY TOO LARGE as PUT Response\n");
606         cs->is_bad_request = GNUNET_NO;
607         cs->is_put_in_progress =GNUNET_NO;
608       }
609       MHD_destroy_response (response);
610       return MHD_YES;
611     }
612
613     if ((*upload_data_size == 0) && (cs->is_put_in_progress == GNUNET_YES) && (cs->is_bad_request == GNUNET_NO))
614     {
615       send_error_to_client = GNUNET_YES;
616       struct GNUNET_MessageHeader * gn_msg = NULL;
617       /*check message and forward here */
618       /* checking size */
619       if (cs->pending_inbound_msg->pos >= sizeof (struct GNUNET_MessageHeader))
620       {
621         gn_msg = GNUNET_malloc (cs->pending_inbound_msg->pos);
622         memcpy (gn_msg,cs->pending_inbound_msg->buf,cs->pending_inbound_msg->pos);
623
624         if ((ntohs(gn_msg->size) == cs->pending_inbound_msg->pos))
625         {
626           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Recieved GNUnet message type %u size %u and payload %u \n",ntohs (gn_msg->type), ntohs (gn_msg->size), ntohs (gn_msg->size)-sizeof(struct GNUNET_MessageHeader));
627           /* forwarding message to transport */
628           plugin->env->receive(plugin->env, &(cs->sender), gn_msg, 1, cs , cs->ip, strlen(cs->ip) );
629           send_error_to_client = GNUNET_NO;
630         }
631       }
632
633       if (send_error_to_client == GNUNET_NO)
634       {
635         response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
636         res = MHD_queue_response (session, MHD_HTTP_OK, response);
637         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 200 OK as PUT Response\n",HTTP_PUT_RESPONSE, strlen (HTTP_PUT_RESPONSE), res );
638         MHD_destroy_response (response);
639       }
640       else
641       {
642         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Recieved malformed message with %u bytes\n", cs->pending_inbound_msg->pos);
643         response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
644         res = MHD_queue_response (session, MHD_HTTP_BAD_REQUEST, response);
645         MHD_destroy_response (response);
646         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 400 BAD REQUEST as PUT Response\n");
647       }
648
649       GNUNET_free_non_null (gn_msg);
650       cs->is_put_in_progress = GNUNET_NO;
651       cs->is_bad_request = GNUNET_NO;
652       cs->pending_inbound_msg->pos = 0;
653       return res;
654     }
655   }
656   if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
657   {
658     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Got GET Request\n");
659     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"URL: `%s'\n",url);
660     response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
661     res = MHD_queue_response (session, MHD_HTTP_OK, response);
662     MHD_destroy_response (response);
663     return res;
664   }
665   return MHD_NO;
666 }
667
668
669 /**
670  * Call MHD to process pending requests and then go back
671  * and schedule the next run.
672  */
673 static void http_daemon_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
674
675 /**
676  * Function that queries MHD's select sets and
677  * starts the task waiting for them.
678  */
679 static GNUNET_SCHEDULER_TaskIdentifier
680 http_daemon_prepare (struct MHD_Daemon *daemon_handle)
681 {
682   GNUNET_SCHEDULER_TaskIdentifier ret;
683   fd_set rs;
684   fd_set ws;
685   fd_set es;
686   struct GNUNET_NETWORK_FDSet *wrs;
687   struct GNUNET_NETWORK_FDSet *wws;
688   struct GNUNET_NETWORK_FDSet *wes;
689   int max;
690   unsigned long long timeout;
691   int haveto;
692   struct GNUNET_TIME_Relative tv;
693
694   FD_ZERO(&rs);
695   FD_ZERO(&ws);
696   FD_ZERO(&es);
697   wrs = GNUNET_NETWORK_fdset_create ();
698   wes = GNUNET_NETWORK_fdset_create ();
699   wws = GNUNET_NETWORK_fdset_create ();
700   max = -1;
701   GNUNET_assert (MHD_YES ==
702                  MHD_get_fdset (daemon_handle,
703                                 &rs,
704                                 &ws,
705                                 &es,
706                                 &max));
707   haveto = MHD_get_timeout (daemon_handle, &timeout);
708   if (haveto == MHD_YES)
709     tv.value = (uint64_t) timeout;
710   else
711     tv = GNUNET_TIME_UNIT_FOREVER_REL;
712   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
713   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
714   GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
715   ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
716                                      GNUNET_SCHEDULER_PRIORITY_HIGH,
717                                      GNUNET_SCHEDULER_NO_TASK,
718                                      tv,
719                                      wrs,
720                                      wws,
721                                      &http_daemon_run,
722                                      daemon_handle);
723   GNUNET_NETWORK_fdset_destroy (wrs);
724   GNUNET_NETWORK_fdset_destroy (wws);
725   GNUNET_NETWORK_fdset_destroy (wes);
726   return ret;
727 }
728
729 /**
730  * Call MHD to process pending requests and then go back
731  * and schedule the next run.
732  */
733 static void http_daemon_run (void *cls,
734                              const struct GNUNET_SCHEDULER_TaskContext *tc)
735 {
736   struct MHD_Daemon *daemon_handle = cls;
737
738   if (daemon_handle == http_daemon_v4)
739     http_task_v4 = GNUNET_SCHEDULER_NO_TASK;
740
741   if (daemon_handle == http_daemon_v6)
742     http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
743
744   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
745     return;
746
747   GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
748   if (daemon_handle == http_daemon_v4)
749     http_task_v4 = http_daemon_prepare (daemon_handle);
750   if (daemon_handle == http_daemon_v6)
751     http_task_v6 = http_daemon_prepare (daemon_handle);
752   return;
753 }
754
755 /**
756  * Removes a message from the linked list of messages
757  * @param ses session to remove message from
758  * @param msg message to remove
759  * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
760  */
761
762 static int remove_http_message(struct Session * ses, struct HTTP_Message * msg)
763 {
764   struct HTTP_Message * cur;
765   struct HTTP_Message * next;
766
767   cur = ses->pending_outbound_msg;
768   next = NULL;
769
770   if (cur == NULL)
771     return GNUNET_SYSERR;
772
773   if (cur == msg)
774   {
775     ses->pending_outbound_msg = cur->next;
776     GNUNET_free (cur->buf);
777     GNUNET_free (cur);
778     cur = NULL;
779     return GNUNET_OK;
780   }
781
782   while (cur->next!=msg)
783   {
784     if (cur->next != NULL)
785       cur = cur->next;
786     else
787       return GNUNET_SYSERR;
788   }
789
790   cur->next = cur->next->next;
791   GNUNET_free (cur->next->buf);
792   GNUNET_free (cur->next);
793   cur->next = NULL;
794   return GNUNET_OK;
795 }
796
797
798 /**
799  * Callback method used with libcurl
800  * Method is called when libcurl needs to read data during sending
801  * @param stream pointer where to write data
802  * @param size size of an individual element
803  * @param nmemb count of elements that can be written to the buffer
804  * @param ptr source pointer, passed to the libcurl handle
805  * @return bytes written to stream
806  */
807 static size_t send_read_callback(void *stream, size_t size, size_t nmemb, void *ptr)
808 {
809   struct Session * ses = ptr;
810   struct HTTP_Message * msg = ses->pending_outbound_msg;
811   unsigned int bytes_sent;
812
813   bytes_sent = 0;
814   if (msg->len > (size * nmemb))
815     return CURL_READFUNC_ABORT;
816
817   if (( msg->pos < msg->len) && (msg->len < (size * nmemb)))
818   {
819     memcpy(stream, msg->buf, msg->len);
820     msg->pos = msg->len;
821     bytes_sent = msg->len;
822   }
823
824   return bytes_sent;
825 }
826
827 /**
828 * Callback method used with libcurl
829 * Method is called when libcurl needs to write data during sending
830 * @param stream pointer where to write data
831 * @param size size of an individual element
832 * @param nmemb count of elements that can be written to the buffer
833 * @param ptr destination pointer, passed to the libcurl handle
834 * @return bytes read from stream
835 */
836 static size_t send_write_callback( void *stream, size_t size, size_t nmemb, void *ptr)
837 {
838   char * data = malloc(size*nmemb +1);
839
840   memcpy( data, stream, size*nmemb);
841   data[size*nmemb] = '\0';
842   /* Just a dummy print for the response recieved for the PUT message */
843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recieved %u bytes: `%s' \n", size * nmemb, data);
844   free (data);
845   return (size * nmemb);
846
847 }
848
849 /**
850  * Function setting up file descriptors and scheduling task to run
851  * @param session session to send data to
852  * @return bytes sent to peer
853  */
854 static size_t send_prepare(struct Session* session );
855
856 /**
857  * Function setting up curl handle and selecting message to send
858  * @param ses session to send data to
859  * @return bytes sent to peer
860  */
861 static ssize_t send_select_init (struct Session* ses  )
862 {
863   char * url;
864   int bytes_sent = 0;
865   CURLMcode mret;
866   struct HTTP_Message * msg;
867
868   /* FIFO selection, send oldest msg first, perhaps priority here?  */
869   msg = ses->pending_outbound_msg;
870
871   url = GNUNET_malloc( 7 + strlen(ses->ip) + 7 + strlen ((char *) &(ses->hash)) + 1);
872   /* FIXME: use correct port number */
873   GNUNET_asprintf(&url,"http://%s:%u/%s",ses->ip,12389, (char *) &(ses->hash));
874 #if DEBUG_CURL
875   curl_easy_setopt(ses->curl_handle, CURLOPT_VERBOSE, 1L);
876 #endif
877   curl_easy_setopt(ses->curl_handle, CURLOPT_URL, url);
878   curl_easy_setopt(ses->curl_handle, CURLOPT_PUT, 1L);
879   curl_easy_setopt(ses->curl_handle, CURLOPT_READFUNCTION, send_read_callback);
880   curl_easy_setopt(ses->curl_handle, CURLOPT_READDATA, ses);
881   curl_easy_setopt(ses->curl_handle, CURLOPT_WRITEFUNCTION, send_write_callback);
882   curl_easy_setopt(ses->curl_handle, CURLOPT_READDATA, ses);
883   curl_easy_setopt(ses->curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t) msg->len);
884   curl_easy_setopt(ses->curl_handle, CURLOPT_TIMEOUT, (long) (timeout.value / 1000 ));
885   curl_easy_setopt(ses->curl_handle, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
886
887   mret = curl_multi_add_handle(multi_handle, ses->curl_handle);
888   if (mret != CURLM_OK)
889   {
890     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
891                 _("%s failed at %s:%d: `%s'\n"),
892                 "curl_multi_add_handle", __FILE__, __LINE__,
893                 curl_multi_strerror (mret));
894     return -1;
895   }
896   bytes_sent = send_prepare (ses );
897   GNUNET_free ( url );
898   return bytes_sent;
899 }
900
901 static void send_execute (void *cls,
902              const struct GNUNET_SCHEDULER_TaskContext *tc)
903 {
904   int running;
905   struct CURLMsg *msg;
906   CURLMcode mret;
907   struct Session * cs = NULL;
908
909   http_task_send = GNUNET_SCHEDULER_NO_TASK;
910   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
911     return;
912
913   do
914     {
915       running = 0;
916       mret = curl_multi_perform (multi_handle, &running);
917       if (running == 0)
918         {
919           do
920             {
921
922               msg = curl_multi_info_read (multi_handle, &running);
923               GNUNET_break (msg != NULL);
924               if (msg == NULL)
925                 break;
926               /* get session for affected curl handle */
927               cs = find_session_by_curlhandle (msg->easy_handle);
928               GNUNET_assert ( cs != NULL );
929               switch (msg->msg)
930                 {
931
932                 case CURLMSG_DONE:
933                   if ( (msg->data.result != CURLE_OK) &&
934                        (msg->data.result != CURLE_GOT_NOTHING) )
935                     {
936
937                     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
938                                _("%s failed for `%s' at %s:%d: `%s'\n"),
939                                "curl_multi_perform",
940                                cs->ip,
941                                __FILE__,
942                                __LINE__,
943                                curl_easy_strerror (msg->data.result));
944                     /* sending msg failed*/
945                     if ( NULL != cs->transmit_cont)
946                       cs->transmit_cont (NULL,&cs->sender,GNUNET_SYSERR);
947                     }
948                   else
949                     {
950                     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
951                                 "Send to %s completed.\n", cs->ip);
952                     if (GNUNET_OK != remove_http_message(cs, cs->pending_outbound_msg))
953                       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message could not be removed from session `%s'", GNUNET_i2s(&cs->sender));
954
955                     curl_easy_cleanup(cs->curl_handle);
956                     cs->curl_handle=NULL;
957
958                     /* send pending messages */
959                     if (cs->pending_outbound_msg != NULL)
960                       send_select_init (cs);
961
962                     /* Calling transmit continuation  */
963                     if ( NULL != cs->transmit_cont)
964                       cs->transmit_cont (NULL,&cs->sender,GNUNET_OK);
965                     }
966                   return;
967                 default:
968                   break;
969                 }
970
971             }
972           while ( (running > 0) );
973         }
974     }
975   while (mret == CURLM_CALL_MULTI_PERFORM);
976   send_prepare(cls);
977 }
978
979
980 /**
981  * Function setting up file descriptors and scheduling task to run
982  * @param ses session to send data to
983  * @return bytes sent to peer
984  */
985 static size_t send_prepare(struct Session* session )
986 {
987   fd_set rs;
988   fd_set ws;
989   fd_set es;
990   int max;
991   struct GNUNET_NETWORK_FDSet *grs;
992   struct GNUNET_NETWORK_FDSet *gws;
993   long to;
994   CURLMcode mret;
995
996   max = -1;
997   FD_ZERO (&rs);
998   FD_ZERO (&ws);
999   FD_ZERO (&es);
1000   mret = curl_multi_fdset (multi_handle, &rs, &ws, &es, &max);
1001   if (mret != CURLM_OK)
1002     {
1003       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1004                   _("%s failed at %s:%d: `%s'\n"),
1005                   "curl_multi_fdset", __FILE__, __LINE__,
1006                   curl_multi_strerror (mret));
1007       return -1;
1008     }
1009   mret = curl_multi_timeout (multi_handle, &to);
1010   if (mret != CURLM_OK)
1011     {
1012       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1013                   _("%s failed at %s:%d: `%s'\n"),
1014                   "curl_multi_timeout", __FILE__, __LINE__,
1015                   curl_multi_strerror (mret));
1016       return -1;
1017     }
1018
1019   grs = GNUNET_NETWORK_fdset_create ();
1020   gws = GNUNET_NETWORK_fdset_create ();
1021   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
1022   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
1023   http_task_send = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1024                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1025                                    GNUNET_SCHEDULER_NO_TASK,
1026                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
1027                                    grs,
1028                                    gws,
1029                                    &send_execute,
1030                                    session);
1031   GNUNET_NETWORK_fdset_destroy (gws);
1032   GNUNET_NETWORK_fdset_destroy (grs);
1033
1034   /* FIXME: return bytes REALLY sent */
1035   return 0;
1036 }
1037
1038 /**
1039  * Function that can be used by the transport service to transmit
1040  * a message using the plugin.
1041  *
1042  * @param cls closure
1043  * @param target who should receive this message
1044  * @param priority how important is the message
1045  * @param msgbuf the message to transmit
1046  * @param msgbuf_size number of bytes in 'msgbuf'
1047  * @param to when should we time out
1048  * @param session which session must be used (or NULL for "any")
1049  * @param addr the address to use (can be NULL if the plugin
1050  *                is "on its own" (i.e. re-use existing TCP connection))
1051  * @param addrlen length of the address in bytes
1052  * @param force_address GNUNET_YES if the plugin MUST use the given address,
1053  *                otherwise the plugin may use other addresses or
1054  *                existing connections (if available)
1055  * @param cont continuation to call once the message has
1056  *        been transmitted (or if the transport is ready
1057  *        for the next transmission call; or if the
1058  *        peer disconnected...)
1059  * @param cont_cls closure for cont
1060  * @return number of bytes used (on the physical network, with overheads);
1061  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1062  *         and does NOT mean that the message was not transmitted (DV)
1063  */
1064 static ssize_t
1065 http_plugin_send (void *cls,
1066                       const struct GNUNET_PeerIdentity *target,
1067                       const char *msgbuf,
1068                       size_t msgbuf_size,
1069                       unsigned int priority,
1070                       struct GNUNET_TIME_Relative to,
1071                       struct Session *session,
1072                       const void *addr,
1073                       size_t addrlen,
1074                       int force_address,
1075                       GNUNET_TRANSPORT_TransmitContinuation cont,
1076                       void *cont_cls)
1077 {
1078   struct Session* ses;
1079   struct Session* ses_temp;
1080   struct HTTP_Message * msg;
1081   struct HTTP_Message * tmp;
1082   int bytes_sent = 0;
1083
1084   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport told plugin to send to peer `%s'\n",GNUNET_i2s(target));
1085
1086   /* find session for peer */
1087   ses = find_session_by_pi (target);
1088   if (NULL != ses )
1089     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Existing session for peer `%s' found\n", GNUNET_i2s(target));
1090   if ( ses == NULL)
1091   {
1092     /* create new session object */
1093
1094     /*FIXME: what is const void * really? Assuming struct sockaddr_in * ! */
1095     ses = create_session((struct sockaddr_in *) addr, target);
1096     ses->is_active = GNUNET_YES;
1097     ses->transmit_cont = cont;
1098
1099     /* Insert session into linked list */
1100     if ( plugin->sessions == NULL)
1101     {
1102       plugin->sessions = ses;
1103       plugin->session_count = 1;
1104     }
1105     ses_temp = plugin->sessions;
1106     while ( ses_temp->next != NULL )
1107     {
1108       ses_temp = ses_temp->next;
1109     }
1110     if (ses_temp != ses )
1111     {
1112       ses_temp->next = ses;
1113       plugin->session_count++;
1114     }
1115     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"New Session `%s' inserted, count %u \n", GNUNET_i2s(target), plugin->session_count);
1116   }
1117
1118   ses->curl_handle = curl_easy_init();
1119   if( NULL == ses->curl_handle)
1120   {
1121     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Getting cURL handle failed\n");
1122     return -1;
1123   }
1124
1125   if ( NULL != cont)
1126     ses->transmit_cont = cont;
1127   timeout = to;
1128   /* setting up message */
1129   msg = GNUNET_malloc (sizeof (struct HTTP_Message));
1130   msg->next = NULL;
1131   msg->len = msgbuf_size;
1132   msg->pos = 0;
1133   msg->buf = GNUNET_malloc (msgbuf_size);
1134   memcpy (msg->buf,msgbuf, msgbuf_size);
1135
1136   /* insert created message in list of pending messages */
1137
1138   if (ses->pending_outbound_msg == NULL)
1139   {
1140     ses->pending_outbound_msg = msg;
1141   }
1142   tmp = ses->pending_outbound_msg;
1143   while ( NULL != tmp->next)
1144   {
1145     tmp = tmp->next;
1146   }
1147   if ( tmp != msg)
1148     tmp->next = msg;
1149
1150   bytes_sent = send_select_init (ses);
1151   return bytes_sent;
1152
1153 }
1154
1155
1156
1157 /**
1158  * Function that can be used to force the plugin to disconnect
1159  * from the given peer and cancel all previous transmissions
1160  * (and their continuationc).
1161  *
1162  * @param cls closure
1163  * @param target peer from which to disconnect
1164  */
1165 static void
1166 http_plugin_disconnect (void *cls,
1167                             const struct GNUNET_PeerIdentity *target)
1168 {
1169   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Plugin: http_plugin_disconnect\n");
1170   // struct Plugin *plugin = cls;
1171   // FIXME
1172 }
1173
1174
1175 /**
1176  * Convert the transports address to a nice, human-readable
1177  * format.
1178  *
1179  * @param cls closure
1180  * @param type name of the transport that generated the address
1181  * @param addr one of the addresses of the host, NULL for the last address
1182  *        the specific address format depends on the transport
1183  * @param addrlen length of the address
1184  * @param numeric should (IP) addresses be displayed in numeric form?
1185  * @param timeout after how long should we give up?
1186  * @param asc function to call on each string
1187  * @param asc_cls closure for asc
1188  */
1189 static void
1190 http_plugin_address_pretty_printer (void *cls,
1191                                         const char *type,
1192                                         const void *addr,
1193                                         size_t addrlen,
1194                                         int numeric,
1195                                         struct GNUNET_TIME_Relative timeout,
1196                                         GNUNET_TRANSPORT_AddressStringCallback
1197                                         asc, void *asc_cls)
1198 {
1199   const struct IPv4HttpAddress *t4;
1200   const struct IPv6HttpAddress *t6;
1201   struct sockaddr_in a4;
1202   struct sockaddr_in6 a6;
1203   char * address;
1204   char * ret;
1205   unsigned int port;
1206
1207   if (addrlen == sizeof (struct IPv6HttpAddress))
1208     {
1209       address = GNUNET_malloc (INET6_ADDRSTRLEN);
1210       t6 = addr;
1211       a6.sin6_addr = t6->ipv6_addr;
1212       inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
1213       port = ntohs(t6->u6_port);
1214     }
1215   else if (addrlen == sizeof (struct IPv4HttpAddress))
1216     {
1217       address = GNUNET_malloc (INET_ADDRSTRLEN);
1218       t4 = addr;
1219       a4.sin_addr.s_addr =  t4->ipv4_addr;
1220       inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
1221       port = ntohs(t4->u_port);
1222     }
1223   else
1224     {
1225       /* invalid address */
1226       GNUNET_break_op (0);
1227       asc (asc_cls, NULL);
1228       return;
1229     }
1230
1231   ret = GNUNET_malloc(strlen(address) +14);
1232   GNUNET_asprintf(&ret,"http://%s:%u/",address,port);
1233   GNUNET_free (address);
1234   asc (asc_cls, ret);
1235 }
1236
1237
1238
1239 /**
1240  * Another peer has suggested an address for this
1241  * peer and transport plugin.  Check that this could be a valid
1242  * address.  If so, consider adding it to the list
1243  * of addresses.
1244  *
1245  * @param cls closure
1246  * @param addr pointer to the address
1247  * @param addrlen length of addr
1248  * @return GNUNET_OK if this is a plausible address for this peer
1249  *         and transport
1250  */
1251 static int
1252 http_plugin_address_suggested (void *cls,
1253                                   void *addr, size_t addrlen)
1254 {
1255   struct IPv4HttpAddress *v4;
1256   struct IPv6HttpAddress *v6;
1257
1258   if ((addrlen != sizeof (struct IPv4HttpAddress)) &&
1259       (addrlen != sizeof (struct IPv6HttpAddress)))
1260     {
1261       GNUNET_break_op (0);
1262       return GNUNET_SYSERR;
1263     }
1264   if (addrlen == sizeof (struct IPv4HttpAddress))
1265     {
1266       v4 = (struct IPv4HttpAddress *) addr;
1267
1268       v4->u_port = ntohs (v4->u_port);
1269       if (v4->u_port != plugin->port_inbound)
1270       {
1271         GNUNET_break_op (0);
1272         return GNUNET_SYSERR;
1273       }
1274     }
1275   else
1276     {
1277       v6 = (struct IPv6HttpAddress *) addr;
1278       if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1279         {
1280           GNUNET_break_op (0);
1281           return GNUNET_SYSERR;
1282         }
1283       v6->u6_port = ntohs (v6->u6_port);
1284       if (v6->u6_port != plugin->port_inbound)
1285       {
1286         GNUNET_break_op (0);
1287         return GNUNET_SYSERR;
1288       }
1289
1290     }
1291   return GNUNET_OK;
1292 }
1293
1294
1295 /**
1296  * Function called for a quick conversion of the binary address to
1297  * a numeric address.  Note that the caller must not free the
1298  * address and that the next call to this function is allowed
1299  * to override the address again.
1300  *
1301  * @param cls closure
1302  * @param addr binary address
1303  * @param addrlen length of the address
1304  * @return string representing the same address
1305  */
1306 static const char*
1307 http_plugin_address_to_string (void *cls,
1308                                    const void *addr,
1309                                    size_t addrlen)
1310 {
1311   const struct IPv4HttpAddress *t4;
1312   const struct IPv6HttpAddress *t6;
1313   struct sockaddr_in a4;
1314   struct sockaddr_in6 a6;
1315   char * address;
1316   char * ret;
1317   unsigned int port;
1318
1319   if (addrlen == sizeof (struct IPv6HttpAddress))
1320     {
1321       address = GNUNET_malloc (INET6_ADDRSTRLEN);
1322       t6 = addr;
1323       a6.sin6_addr = t6->ipv6_addr;
1324       inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
1325       port = ntohs(t6->u6_port);
1326     }
1327   else if (addrlen == sizeof (struct IPv4HttpAddress))
1328     {
1329       address = GNUNET_malloc (INET_ADDRSTRLEN);
1330       t4 = addr;
1331       a4.sin_addr.s_addr =  t4->ipv4_addr;
1332       inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
1333       port = ntohs(t4->u_port);
1334     }
1335   else
1336     {
1337       /* invalid address */
1338       return NULL;
1339     }
1340
1341   ret = GNUNET_malloc(strlen(address) +6);
1342   GNUNET_asprintf(&ret,"%s:%u",address,port);
1343   GNUNET_free (address);
1344   return ret;
1345 }
1346
1347 /**
1348  * Add the IP of our network interface to the list of
1349  * our external IP addresses.
1350  *
1351  * @param cls the 'struct Plugin*'
1352  * @param name name of the interface
1353  * @param isDefault do we think this may be our default interface
1354  * @param addr address of the interface
1355  * @param addrlen number of bytes in addr
1356  * @return GNUNET_OK to continue iterating
1357  */
1358 static int
1359 process_interfaces (void *cls,
1360                     const char *name,
1361                     int isDefault,
1362                     const struct sockaddr *addr, socklen_t addrlen)
1363 {
1364   struct IPv4HttpAddress t4;
1365   struct IPv6HttpAddress t6;
1366   int af;
1367   void *arg;
1368   uint16_t args;
1369
1370
1371
1372   af = addr->sa_family;
1373   if (af == AF_INET)
1374     {
1375       if (INADDR_LOOPBACK == ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr))
1376       {
1377         /* skip loopback addresses */
1378         return GNUNET_OK;
1379       }
1380       t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1381       t4.u_port = htons (plugin->port_inbound);
1382       arg = &t4;
1383       args = sizeof (t4);
1384     }
1385   else if (af == AF_INET6)
1386     {
1387       if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1388         {
1389           /* skip link local addresses */
1390           return GNUNET_OK;
1391         }
1392       if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))
1393         {
1394           /* skip loopback addresses */
1395           return GNUNET_OK;
1396         }
1397       memcpy (&t6.ipv6_addr,
1398               &((struct sockaddr_in6 *) addr)->sin6_addr,
1399               sizeof (struct in6_addr));
1400       t6.u6_port = htons (plugin->port_inbound);
1401       arg = &t6;
1402       args = sizeof (t6);
1403     }
1404   else
1405     {
1406       GNUNET_break (0);
1407       return GNUNET_OK;
1408     }
1409   plugin->env->notify_address(plugin->env->cls,"http",arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
1410
1411   return GNUNET_OK;
1412 }
1413
1414 /**
1415  * Exit point from the plugin.
1416  */
1417 void *
1418 libgnunet_plugin_transport_http_done (void *cls)
1419 {
1420   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1421   struct Plugin *plugin = api->cls;
1422   struct Session * cs;
1423   struct Session * cs_next;
1424   CURLMcode mret;
1425
1426   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unloading http plugin...\n");
1427
1428   if ( http_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1429   {
1430     GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_v4);
1431     http_task_v4 = GNUNET_SCHEDULER_NO_TASK;
1432   }
1433
1434   if ( http_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1435   {
1436     GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_v6);
1437     http_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1438   }
1439
1440   if ( http_task_send != GNUNET_SCHEDULER_NO_TASK)
1441   {
1442     GNUNET_SCHEDULER_cancel(plugin->env->sched, http_task_send);
1443     http_task_send = GNUNET_SCHEDULER_NO_TASK;
1444   }
1445
1446   if (http_daemon_v4 != NULL)
1447   {
1448     MHD_stop_daemon (http_daemon_v4);
1449     http_daemon_v4 = NULL;
1450   }
1451   if (http_daemon_v6 != NULL)
1452   {
1453     MHD_stop_daemon (http_daemon_v6);
1454     http_daemon_v6 = NULL;
1455   }
1456
1457   mret = curl_multi_cleanup(multi_handle);
1458   if ( CURLM_OK != mret)
1459     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed");
1460
1461   /* free all sessions */
1462   cs = plugin->sessions;
1463
1464   while ( NULL != cs)
1465     {
1466       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing session to `%s'\n",cs->ip);
1467
1468       cs_next = cs->next;
1469       /* freeing messages */
1470       struct HTTP_Message *cur;
1471       struct HTTP_Message *tmp;
1472       cur = cs->pending_outbound_msg;
1473
1474       while (cur != NULL)
1475       {
1476          tmp = cur->next;
1477          if (NULL != cur->buf)
1478            GNUNET_free (cur->buf);
1479          GNUNET_free (cur);
1480          cur = tmp;
1481       }
1482       GNUNET_free (cs->pending_inbound_msg->buf);
1483       GNUNET_free (cs->pending_inbound_msg);
1484       GNUNET_free (cs->ip);
1485       GNUNET_free (cs->addr);
1486       GNUNET_free (cs);
1487       plugin->session_count--;
1488       cs = cs_next;
1489
1490     }
1491
1492   /* GNUNET_SERVICE_stop (plugin->service); */
1493   GNUNET_free (hostname);
1494   GNUNET_free (plugin);
1495   GNUNET_free (api);
1496   return NULL;
1497 }
1498
1499
1500 /**
1501  * Entry point for the plugin.
1502  */
1503 void *
1504 libgnunet_plugin_transport_http_init (void *cls)
1505 {
1506   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1507   struct GNUNET_TRANSPORT_PluginFunctions *api;
1508   struct GNUNET_SERVICE_Context *service;
1509   unsigned int timeout;
1510   struct GNUNET_TIME_Relative gn_timeout;
1511   long long unsigned int port;
1512
1513   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting http plugin...\n");
1514
1515   service = NULL;
1516   /*
1517   service = GNUNET_SERVICE_start ("transport-http", env->sched, env->cfg);
1518   if (service == NULL)
1519     {
1520       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "", _
1521                        ("Failed to start service for `%s' transport plugin.\n"),
1522                        "http");
1523       return NULL;
1524     }
1525     */
1526
1527   plugin = GNUNET_malloc (sizeof (struct Plugin));
1528   plugin->env = env;
1529   plugin->sessions = NULL;
1530   plugin->service = service;
1531   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1532   api->cls = plugin;
1533   api->send = &http_plugin_send;
1534   api->disconnect = &http_plugin_disconnect;
1535   api->address_pretty_printer = &http_plugin_address_pretty_printer;
1536   api->check_address = &http_plugin_address_suggested;
1537   api->address_to_string = &http_plugin_address_to_string;
1538
1539   hostname = GNUNET_RESOLVER_local_fqdn_get ();
1540
1541   /* Hashing our identity to use it in URLs */
1542   GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &my_ascii_hash_ident);
1543
1544   /* Reading port number from config file */
1545   if ((GNUNET_OK !=
1546        GNUNET_CONFIGURATION_get_value_number (env->cfg,
1547                                               "transport-http",
1548                                               "PORT",
1549                                               &port)) ||
1550       (port > 65535) )
1551     {
1552       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1553                        "http",
1554                        _
1555                        ("Require valid port number for transport plugin `%s' in configuration!\n"),
1556                        "transport-http");
1557       libgnunet_plugin_transport_http_done (api);
1558       return NULL;
1559     }
1560   plugin->port_inbound = port;
1561   gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
1562   timeout = ( gn_timeout.value / 1000);
1563   if ((http_daemon_v4 == NULL) && (http_daemon_v6 == NULL) && (port != 0))
1564     {
1565     http_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
1566                                        port,
1567                                        &acceptPolicyCallback,
1568                                        NULL , &accessHandlerCallback, NULL,
1569                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
1570                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1571                                        MHD_OPTION_CONNECTION_TIMEOUT, timeout,
1572                                        /* FIXME: set correct limit */
1573                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
1574                                        MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
1575                                        MHD_OPTION_END);
1576     http_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
1577                                        port,
1578                                        &acceptPolicyCallback,
1579                                        NULL , &accessHandlerCallback, NULL,
1580                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
1581                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1582                                        MHD_OPTION_CONNECTION_TIMEOUT, timeout,
1583                                        /* FIXME: set correct limit */
1584                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
1585                                        MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
1586                                        MHD_OPTION_END);
1587     }
1588   if (http_daemon_v4 != NULL)
1589     http_task_v4 = http_daemon_prepare (http_daemon_v4);
1590   if (http_daemon_v6 != NULL)
1591     http_task_v6 = http_daemon_prepare (http_daemon_v6);
1592
1593   if (http_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1594     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 on port %u\n",port);
1595   if (http_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1596     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 on port %u\n",port);
1597
1598
1599   /* Initializing cURL */
1600   multi_handle = curl_multi_init();
1601   if ( NULL == multi_handle )
1602   {
1603     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1604                      "http",
1605                      _("Could not initialize curl multi handle, failed to start http plugin!\n"),
1606                      "transport-http");
1607     libgnunet_plugin_transport_http_done (api);
1608     return NULL;
1609   }
1610
1611   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
1612
1613   return api;
1614 }
1615
1616 /* end of plugin_transport_template.c */