(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 3, 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_http.c
23  * @brief http transport service plugin
24  * @author Matthias Wachs
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_service_lib.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet_resolver_service.h"
35 #include "gnunet_server_lib.h"
36 #include "gnunet_container_lib.h"
37 #include "plugin_transport.h"
38 #include "gnunet_os_lib.h"
39 #include "microhttpd.h"
40 #include <curl/curl.h>
41
42
43 #define DEBUG_CURL GNUNET_YES
44 #define DEBUG_HTTP GNUNET_NO
45
46 #define INBOUND GNUNET_NO
47 #define OUTBOUND GNUNET_YES
48
49 /**
50  * Text of the response sent back after the last bytes of a PUT
51  * request have been received (just to formally obey the HTTP
52  * protocol).
53  */
54 #define HTTP_PUT_RESPONSE "Thank you!"
55
56 /**
57  * After how long do we expire an address that we
58  * learned from another peer if it is not reconfirmed
59  * by anyone?
60  */
61 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
62
63 /**
64  * Page returned if request invalid
65  */
66 #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>"
67
68 /**
69  * Timeout for a http connect
70  */
71 #define HTTP_CONNECT_TIMEOUT 30
72
73 /**
74  * Network format for IPv4 addresses.
75  */
76 struct IPv4HttpAddress
77 {
78   /**
79    * IPv4 address, in network byte order.
80    */
81   uint32_t ipv4_addr GNUNET_PACKED;
82
83   /**
84    * Port number, in network byte order.
85    */
86   uint16_t u_port GNUNET_PACKED;
87
88 };
89
90
91 /**
92  * Network format for IPv6 addresses.
93  */
94 struct IPv6HttpAddress
95 {
96   /**
97    * IPv6 address.
98    */
99   struct in6_addr ipv6_addr GNUNET_PACKED;
100
101   /**
102    * Port number, in network byte order.
103    */
104   uint16_t u6_port GNUNET_PACKED;
105
106 };
107
108
109 /**
110  *  Message to send using http
111  */
112 struct HTTP_Message
113 {
114   /**
115    * next pointer for double linked list
116    */
117   struct HTTP_Message * next;
118
119   /**
120    * previous pointer for double linked list
121    */
122   struct HTTP_Message * prev;
123
124   /**
125    * buffer containing data to send
126    */
127   char *buf;
128
129   /**
130    * amount of data already sent
131    */
132   size_t pos;
133
134   /**
135    * buffer length
136    */
137   size_t size;
138
139   /**
140    * Continuation function to call once the transmission buffer
141    * has again space available.  NULL if there is no
142    * continuation to call.
143    */
144   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
145
146   /**
147    * Closure for transmit_cont.
148    */
149   void *transmit_cont_cls;
150 };
151
152
153 struct HTTP_PeerContext
154 {
155   struct GNUNET_PeerIdentity identity;
156
157   /**
158    * Pointer to the global plugin struct.
159    */
160   struct Plugin *plugin;
161
162   struct HTTP_Session * head;
163   struct HTTP_Session * tail;
164 };
165
166
167 struct HTTP_Session
168 {
169   struct HTTP_Session * next;
170   struct HTTP_Session * prev;
171
172   void * addr;
173   size_t addrlen;
174
175   /**
176    * target url
177    */
178   char * url;
179
180   /**
181    * Message queue for outbound messages
182    * head of queue
183    */
184   struct HTTP_Message * pending_msgs_head;
185
186   /**
187    * Message queue for outbound messages
188    * tail of queue
189    */
190   struct HTTP_Message * pending_msgs_tail;
191
192   /**
193    * partner peer this connection belongs to
194    */
195   struct HTTP_PeerContext * peercontext;
196
197   /**
198    * message stream tokenizer for incoming data
199    */
200   struct GNUNET_SERVER_MessageStreamTokenizer *msgtok;
201
202   /**
203    * session direction
204    * outbound: GNUNET_YES
205    * inbound : GNUNET_NO
206    */
207   unsigned int direction;
208
209   unsigned int send_connected;
210   unsigned int send_active;
211   unsigned int recv_connected;
212   unsigned int recv_active;
213
214   /**
215    * entity managing sending data
216    */
217   void * send_endpoint;
218
219   /**
220    * entity managing recieving data
221    */
222   void * recv_endpoint;
223 };
224
225
226 /**
227  * Session handle for connections.
228  */
229 struct Session
230 {
231
232   /**
233    * API requirement.
234    */
235   struct SessionHeader header;
236
237   /**
238    * Stored in a linked list.
239    */
240   struct Session *next;
241
242   /**
243    * Pointer to the global plugin struct.
244    */
245   struct Plugin *plugin;
246
247   /**
248    * To whom are we talking to (set to our identity
249    * if we are still waiting for the welcome message)
250    */
251   struct GNUNET_PeerIdentity identity;
252
253   /**
254    * Did we initiate the connection (GNUNET_YES) or the other peer (GNUNET_NO)?
255    */
256   int is_client;
257
258   /**
259    * At what time did we reset last_received last?
260    */
261   struct GNUNET_TIME_Absolute last_quota_update;
262
263   /**
264    * How many bytes have we received since the "last_quota_update"
265    * timestamp?
266    */
267   uint64_t last_received;
268
269   /**
270    * Number of bytes per ms that this peer is allowed
271    * to send to us.
272    */
273   uint32_t quota;
274
275   /**
276    * Encoded hash
277    */
278   struct GNUNET_CRYPTO_HashAsciiEncoded hash;
279 };
280
281 /**
282  * Encapsulation of all of the state of the plugin.
283  */
284 struct Plugin
285 {
286   /**
287    * Our environment.
288    */
289   struct GNUNET_TRANSPORT_PluginEnvironment *env;
290
291   unsigned int port_inbound;
292
293   struct GNUNET_CONTAINER_MultiHashMap *peers;
294
295   /**
296    * Daemon for listening for new IPv4 connections.
297    */
298   struct MHD_Daemon *http_server_daemon_v4;
299
300   /**
301    * Daemon for listening for new IPv6connections.
302    */
303   struct MHD_Daemon *http_server_daemon_v6;
304
305   /**
306    * Our primary task for http daemon handling IPv4 connections
307    */
308   GNUNET_SCHEDULER_TaskIdentifier http_server_task_v4;
309
310   /**
311    * Our primary task for http daemon handling IPv6 connections
312    */
313   GNUNET_SCHEDULER_TaskIdentifier http_server_task_v6;
314
315   /**
316    * The task sending data
317    */
318   GNUNET_SCHEDULER_TaskIdentifier http_server_task_send;
319
320   /**
321    * cURL Multihandle
322    */
323   CURLM * multi_handle;
324
325   /**
326    * Our ASCII encoded, hashed peer identity
327    * This string is used to distinguish between connections and is added to the urls
328    */
329   struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
330 };
331
332
333 /**
334  * Function called for a quick conversion of the binary address to
335  * a numeric address.  Note that the caller must not free the
336  * address and that the next call to this function is allowed
337  * to override the address again.
338  *
339  * @param cls closure
340  * @param addr binary address
341  * @param addrlen length of the address
342  * @return string representing the same address
343  */
344 static const char*
345 http_plugin_address_to_string (void *cls,
346                                    const void *addr,
347                                    size_t addrlen);
348
349 static char * create_url(void * cls, const void * addr, size_t addrlen)
350 {
351   struct Plugin *plugin = cls;
352   char *url = NULL;
353
354   GNUNET_assert ((addr!=NULL) && (addrlen != 0));
355   GNUNET_asprintf(&url,
356                   "http://%s/%s",
357                   http_plugin_address_to_string(NULL, addr, addrlen),
358                   (char *) (&plugin->my_ascii_hash_ident));
359
360   return url;
361 }
362
363 /**
364  * Removes a message from the linked list of messages
365  * @param con connection to remove message from
366  * @param msg message to remove
367  * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
368  */
369
370 static int remove_http_message(struct HTTP_Session * ps, struct HTTP_Message * msg)
371 {
372   GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
373   GNUNET_free(msg);
374   return GNUNET_OK;
375 }
376
377 static struct HTTP_Session * get_HTTP_Session (void * cls, struct HTTP_PeerContext *pc, const void * addr, size_t addr_len)
378 {
379   struct HTTP_Session * cc = pc->head;
380   struct HTTP_Session * con = NULL;
381   unsigned int count = 0;
382
383   GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
384   while (cc!=NULL)
385   {
386     if (addr_len == cc->addrlen)
387     {
388       if (0 == memcmp(cc->addr, addr, addr_len))
389       {
390         con = cc;
391         break;
392       }
393     }
394     count++;
395     cc=cc->next;
396   }
397   return con;
398 }
399
400
401 /**
402  * Callback called by MHD when a connection is terminated
403  */
404 static void requestCompletedCallback (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
405 {
406   struct HTTP_Session * ps = *httpSessionCache;
407   if (ps == NULL)
408     return;
409   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection from peer `%s' was terminated\n",GNUNET_i2s(&ps->peercontext->identity));
410   /* session set to inactive */
411   //ps-> = GNUNET_NO;
412   //con->is_bad_request = GNUNET_NO;
413 }
414
415 static void mhd_write_mst_cb (void *cls,
416                               void *client,
417                               const struct GNUNET_MessageHeader *message)
418 {
419
420   struct HTTP_Session *ps  = cls;
421   struct HTTP_PeerContext *pc = ps->peercontext;
422   GNUNET_assert(ps != NULL);
423   GNUNET_assert(pc != NULL);
424
425   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426               "Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
427               ntohs(message->type),
428               ntohs(message->size),
429               GNUNET_i2s(&(ps->peercontext)->identity),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
430 /*
431   pc->plugin->env->receive (ps->peercontext->plugin->env->cls,
432                             &pc->identity,
433                             message, 1, ps,
434                             ps->addr,
435                             ps->addrlen);*/
436 }
437
438 static void curl_write_mst_cb  (void *cls,
439                                 void *client,
440                                 const struct GNUNET_MessageHeader *message)
441 {
442   struct HTTP_Session *ps  = cls;
443   struct HTTP_PeerContext *pc = ps->peercontext;
444   GNUNET_assert(ps != NULL);
445   GNUNET_assert(pc != NULL);
446
447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448               "Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
449               ntohs(message->type),
450               ntohs(message->size),
451               GNUNET_i2s(&(pc->identity)),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
452 /*
453   pc->plugin->env->receive (pc->plugin->env->cls,
454                             &pc->identity,
455                             message, 1, ps,
456                             ps->addr,
457                             ps->addrlen);*/
458 }
459
460
461 /**
462  * Check if ip is allowed to connect.
463  */
464 static int
465 acceptPolicyCallback (void *cls,
466                       const struct sockaddr *addr, socklen_t addr_len)
467 {
468 #if 0
469   struct Plugin *plugin = cls;
470 #endif
471   /* Every connection is accepted, nothing more to do here */
472   return MHD_YES;
473 }
474
475 int server_read_callback (void *cls, uint64_t pos, char *buf, int max)
476 {
477   int bytes_read = 0;
478
479   struct HTTP_Session * ps = cls;
480   struct HTTP_PeerContext * pc;
481   struct HTTP_Message * msg;
482   int res;res=5;
483
484   GNUNET_assert (ps!=NULL);
485   pc = ps->peercontext;
486   msg = ps->pending_msgs_tail;
487
488   if (msg!=NULL)
489   {
490     if ((msg->size-msg->pos) <= max)
491       {
492         memcpy(buf,&msg->buf[pos],(msg->size-msg->pos));
493         pos+=(msg->size-msg->pos);
494       }
495       else
496       {
497         memcpy(buf,&msg->buf[pos],max);
498         pos+=max;
499       }
500
501       if (msg->pos==msg->size)
502       {
503         if (NULL!=msg->transmit_cont)
504           msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
505         res = remove_http_message(ps,msg);
506       }
507   }
508   return bytes_read;
509 }
510
511 /**
512  * Process GET or PUT request received via MHD.  For
513  * GET, queue response that will send back our pending
514  * messages.  For PUT, process incoming data and send
515  * to GNUnet core.  In either case, check if a session
516  * already exists and create a new one if not.
517  */
518 static int
519 accessHandlerCallback (void *cls,
520                        struct MHD_Connection *mhd_connection,
521                        const char *url,
522                        const char *method,
523                        const char *version,
524                        const char *upload_data,
525                        size_t * upload_data_size, void **httpSessionCache)
526 {
527   struct Plugin *plugin = cls;
528   struct MHD_Response *response;
529   const union MHD_ConnectionInfo * conn_info;
530
531   struct sockaddr_in  *addrin;
532   struct sockaddr_in6 *addrin6;
533
534   char address[INET6_ADDRSTRLEN+14];
535   struct GNUNET_PeerIdentity pi_in;
536
537   struct IPv4HttpAddress ipv4addr;
538   struct IPv6HttpAddress ipv6addr;
539
540   struct HTTP_PeerContext *pc;
541   struct HTTP_Session *ps;
542
543   int res = GNUNET_NO;
544   int send_error_to_client;
545   void * addr;
546   size_t addr_len;
547
548   GNUNET_assert(cls !=NULL);
549   send_error_to_client = GNUNET_NO;
550
551   if (NULL == *httpSessionCache)
552   {
553     /* check url for peer identity , if invalid send HTTP 404*/
554     res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
555     if ( GNUNET_SYSERR == res )
556     {
557       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
558       res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
559       MHD_destroy_response (response);
560       if (res == MHD_YES)
561         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, sent HTTP 1.1/404\n");
562       else
563         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, could not send error\n");
564       return res;
565     }
566   }
567   else
568   {
569     ps = *httpSessionCache;
570     pc = ps->peercontext;
571   }
572
573   if (NULL == *httpSessionCache)
574   {
575     /* get peer context */
576     pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &pi_in.hashPubKey);
577     /* Peer unknown */
578     if (pc==NULL)
579     {
580       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"RECV: CREATING NEW PEER CONTEXT\n");
581       pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
582       pc->plugin = plugin;
583       memcpy(&pc->identity, &pi_in, sizeof(struct GNUNET_PeerIdentity));
584       GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
585     }
586     else
587     {
588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"RECV: PEER CONTEXT FOUND\n");
589     }
590
591     conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
592     /* Incoming IPv4 connection */
593     if ( AF_INET == conn_info->client_addr->sin_family)
594     {
595       addrin = conn_info->client_addr;
596       inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
597       memcpy(&ipv4addr.ipv4_addr,&(addrin->sin_addr),sizeof(struct in_addr));
598       ipv4addr.u_port = addrin->sin_port;
599       addr = &ipv4addr;
600       addr_len = sizeof(struct IPv4HttpAddress);
601       //con = session_check_inbound_address (plugin, cs, (const void *) &ipv4addr, sizeof (struct IPv4HttpAddress));
602     }
603     /* Incoming IPv6 connection */
604     if ( AF_INET6 == conn_info->client_addr->sin_family)
605     {
606       addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
607       inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
608       memcpy(&ipv6addr.ipv6_addr,&(addrin6->sin6_addr),sizeof(struct in6_addr));
609       ipv6addr.u6_port = addrin6->sin6_port;
610       addr = &ipv6addr;
611       addr_len = sizeof(struct IPv6HttpAddress);
612     }
613     /* Set closure and update current session*/
614     ps = get_HTTP_Session(plugin, pc, addr, addr_len);
615     if (ps==NULL)
616     {
617       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"RECV: CREATING NEW SESSION %s\n",http_plugin_address_to_string(NULL, addr, addr_len));
618       ps = GNUNET_malloc(sizeof (struct HTTP_Session));
619       ps->addr = GNUNET_malloc(addr_len);
620       memcpy(ps->addr,addr,addr_len);
621       ps->addrlen = addr_len;
622       ps->direction=INBOUND;
623       ps->pending_msgs_head = NULL;
624       ps->pending_msgs_tail = NULL;
625       ps->send_connected=GNUNET_NO;
626       ps->send_active=GNUNET_NO;
627       ps->recv_connected=GNUNET_NO;
628       ps->recv_active=GNUNET_NO;
629       ps->peercontext=pc;
630       ps->url = create_url (plugin, ps->addr, ps->addrlen);
631       GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
632     }
633     else
634     {
635       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"RECV: SESSION CONTEXT FOUND\n");
636     }
637
638     *httpSessionCache = ps;
639     if (ps->msgtok==NULL)
640       ps->msgtok = GNUNET_SERVER_mst_create (&mhd_write_mst_cb, ps);
641
642     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",
643                 method,
644                 GNUNET_i2s(&pc->identity),
645                 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen));
646   }
647
648   /* Is it a PUT or a GET request */
649   if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
650   {
651     if ((*upload_data_size == 0) && (ps->recv_active==GNUNET_NO))
652     {
653       ps->recv_active = GNUNET_YES;
654       return MHD_YES;
655     }
656
657     /* Transmission of all data complete */
658     if ((*upload_data_size == 0) && (ps->recv_active == GNUNET_YES))
659     {
660       response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
661       res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
662       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 200 OK as PUT Response\n",HTTP_PUT_RESPONSE, strlen (HTTP_PUT_RESPONSE), res );
663       MHD_destroy_response (response);
664       ps->recv_active=GNUNET_NO;
665       return MHD_YES;
666     }
667
668     /* Recieving data */
669     if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES))
670     {
671       res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
672       (*upload_data_size) = 0;
673       return MHD_YES;
674     }
675     else
676       return MHD_NO;
677   }
678   if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
679   {
680     response = MHD_create_response_from_callback(-1,32 * 1024, &server_read_callback, ps, NULL);
681     res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
682     MHD_destroy_response (response);
683
684     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",
685                 method,
686                 GNUNET_i2s(&pc->identity),
687                 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen));
688     return res;
689   }
690   return MHD_NO;
691 }
692
693
694 /**
695  * Call MHD to process pending ipv4 requests and then go back
696  * and schedule the next run.
697  */
698 static void http_server_daemon_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
699 /**
700  * Call MHD to process pending ipv6 requests and then go back
701  * and schedule the next run.
702  */
703 static void http_server_daemon_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
704
705 /**
706  * Function that queries MHD's select sets and
707  * starts the task waiting for them.
708  */
709 static GNUNET_SCHEDULER_TaskIdentifier
710 http_server_daemon_prepare (void * cls, struct MHD_Daemon *daemon_handle)
711 {
712   struct Plugin *plugin = cls;
713   GNUNET_SCHEDULER_TaskIdentifier ret;
714   fd_set rs;
715   fd_set ws;
716   fd_set es;
717   struct GNUNET_NETWORK_FDSet *wrs;
718   struct GNUNET_NETWORK_FDSet *wws;
719   struct GNUNET_NETWORK_FDSet *wes;
720   int max;
721   unsigned long long timeout;
722   int haveto;
723   struct GNUNET_TIME_Relative tv;
724
725   GNUNET_assert(cls !=NULL);
726   ret = GNUNET_SCHEDULER_NO_TASK;
727   FD_ZERO(&rs);
728   FD_ZERO(&ws);
729   FD_ZERO(&es);
730   wrs = GNUNET_NETWORK_fdset_create ();
731   wes = GNUNET_NETWORK_fdset_create ();
732   wws = GNUNET_NETWORK_fdset_create ();
733   max = -1;
734   GNUNET_assert (MHD_YES ==
735                  MHD_get_fdset (daemon_handle,
736                                 &rs,
737                                 &ws,
738                                 &es,
739                                 &max));
740   haveto = MHD_get_timeout (daemon_handle, &timeout);
741   if (haveto == MHD_YES)
742     tv.value = (uint64_t) timeout;
743   else
744     tv = GNUNET_TIME_UNIT_FOREVER_REL;
745   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
746   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
747   GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
748   if (daemon_handle == plugin->http_server_daemon_v4)
749   {
750     ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
751                                        GNUNET_SCHEDULER_PRIORITY_DEFAULT,
752                                        GNUNET_SCHEDULER_NO_TASK,
753                                        tv,
754                                        wrs,
755                                        wws,
756                                        &http_server_daemon_v4_run,
757                                        plugin);
758   }
759   if (daemon_handle == plugin->http_server_daemon_v6)
760   {
761     ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
762                                        GNUNET_SCHEDULER_PRIORITY_DEFAULT,
763                                        GNUNET_SCHEDULER_NO_TASK,
764                                        tv,
765                                        wrs,
766                                        wws,
767                                        &http_server_daemon_v6_run,
768                                        plugin);
769   }
770   GNUNET_NETWORK_fdset_destroy (wrs);
771   GNUNET_NETWORK_fdset_destroy (wws);
772   GNUNET_NETWORK_fdset_destroy (wes);
773   return ret;
774 }
775
776 /**
777  * Call MHD to process pending requests and then go back
778  * and schedule the next run.
779  */
780 static void http_server_daemon_v4_run (void *cls,
781                              const struct GNUNET_SCHEDULER_TaskContext *tc)
782 {
783   struct Plugin *plugin = cls;
784
785   GNUNET_assert(cls !=NULL);
786   if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
787     plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
788
789   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
790     return;
791
792   GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v4));
793   plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
794   return;
795 }
796
797
798 /**
799  * Call MHD to process pending requests and then go back
800  * and schedule the next run.
801  */
802 static void http_server_daemon_v6_run (void *cls,
803                              const struct GNUNET_SCHEDULER_TaskContext *tc)
804 {
805   struct Plugin *plugin = cls;
806
807   GNUNET_assert(cls !=NULL);
808   if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
809     plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
810
811   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
812     return;
813
814   GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v6));
815   plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
816   return;
817 }
818
819
820 static size_t curl_header_function( void *ptr, size_t size, size_t nmemb, void *stream)
821 {
822   struct HTTP_Session * ps = stream;
823
824   char * tmp;
825   size_t len = size * nmemb;
826   long http_result = 0;
827   int res;
828
829   /* Getting last http result code */
830   if (ps->recv_connected==GNUNET_NO)
831   {
832     GNUNET_assert(NULL!=ps);
833     res = curl_easy_getinfo(ps->recv_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
834     if (CURLE_OK == res)
835     {
836       if (http_result == 200)
837       {
838         ps->recv_connected = GNUNET_YES;
839         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connected\n",ps);
840       }
841     }
842   }
843
844   tmp = NULL;
845   if ((size * nmemb) < SIZE_MAX)
846     tmp = GNUNET_malloc (len+1);
847
848   if ((tmp != NULL) && (len > 0))
849   {
850     memcpy(tmp,ptr,len);
851     if (len>=2)
852     {
853       if (tmp[len-2] == 13)
854         tmp[len-2]= '\0';
855     }
856 #if DEBUG_HTTP
857     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s' %u \n",tmp, http_result);
858 #endif
859   }
860   if (NULL != tmp)
861     GNUNET_free (tmp);
862
863   return size * nmemb;
864 }
865
866 /**
867  * Callback method used with libcurl
868  * Method is called when libcurl needs to read data during sending
869  * @param stream pointer where to write data
870  * @param size size of an individual element
871  * @param nmemb count of elements that can be written to the buffer
872  * @param ptr source pointer, passed to the libcurl handle
873  * @return bytes written to stream
874  */
875 static size_t send_curl_read_callback(void *stream, size_t size, size_t nmemb, void *ptr)
876 {
877   struct HTTP_Session * ps = ptr;
878   struct HTTP_Message * msg = ps->pending_msgs_tail;
879   size_t bytes_sent;
880   size_t len;
881
882   if (ps->pending_msgs_tail == NULL)
883   {
884     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: No Message to send, pausing connection\n",ps);
885     ps->send_active = GNUNET_NO;
886     return CURL_READFUNC_PAUSE;
887   }
888
889   msg = ps->pending_msgs_tail;
890   /* data to send */
891   if (msg->pos < msg->size)
892   {
893     /* data fit in buffer */
894     if ((msg->size - msg->pos) <= (size * nmemb))
895     {
896       len = (msg->size - msg->pos);
897       memcpy(stream, &msg->buf[msg->pos], len);
898       msg->pos += len;
899       bytes_sent = len;
900     }
901     else
902     {
903       len = size*nmemb;
904       memcpy(stream, &msg->buf[msg->pos], len);
905       msg->pos += len;
906       bytes_sent = len;
907     }
908   }
909   /* no data to send */
910   else
911   {
912     bytes_sent = 0;
913   }
914
915   if ( msg->pos == msg->size)
916   {
917     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Message with %u bytes sent, removing message from queue \n",ps, msg->pos);
918     /* Calling transmit continuation  */
919     if (( NULL != ps->pending_msgs_tail) && (NULL != ps->pending_msgs_tail->transmit_cont))
920       msg->transmit_cont (ps->pending_msgs_tail->transmit_cont_cls,&(ps->peercontext)->identity,GNUNET_OK);
921     remove_http_message(ps, msg);
922   }
923   return bytes_sent;
924 }
925
926 /**
927 * Callback method used with libcurl
928 * Method is called when libcurl needs to write data during sending
929 * @param stream pointer where to write data
930 * @param size size of an individual element
931 * @param nmemb count of elements that can be written to the buffer
932 * @param ptr destination pointer, passed to the libcurl handle
933 * @return bytes read from stream
934 */
935 static size_t send_curl_write_callback( void *stream, size_t size, size_t nmemb, void *ptr)
936 {
937   struct HTTP_Session * ps = ptr;
938
939   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes recieved\n",ps, size*nmemb);
940   GNUNET_SERVER_mst_receive(ps->msgtok, ps, stream, size*nmemb, GNUNET_NO, GNUNET_NO);
941
942   return (size * nmemb);
943
944 }
945
946 /**
947  * Function setting up file descriptors and scheduling task to run
948  * @param cls closure
949  * @param ses session to send data to
950  * @return bytes sent to peer
951  */
952 static size_t send_schedule(void *cls, struct Session* ses );
953
954
955
956 /**
957  * Function setting up curl handle and selecting message to send
958  * @param cls plugin
959  * @param ses session to send data to
960  * @param con connection
961  * @return bytes sent to peer
962  */
963 static ssize_t send_check_connections (void *cls, struct Session* ses , struct HTTP_Session *ps)
964 {
965   struct Plugin *plugin = cls;
966   int bytes_sent = 0;
967   CURLMcode mret;
968   struct HTTP_Message * msg;
969   struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
970
971   GNUNET_assert(cls !=NULL);
972
973   if (ps->direction == OUTBOUND)
974   {
975     /* Check if session is connected to receive data, otherwise connect to peer */
976     if (ps->recv_connected == GNUNET_NO)
977     {
978         if (ps->recv_endpoint == NULL)
979         {
980           ps->recv_endpoint = curl_easy_init();
981 #if DEBUG_CURL
982         curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L);
983 #endif
984         curl_easy_setopt(ps->recv_endpoint, CURLOPT_URL, ps->url);
985         curl_easy_setopt(ps->recv_endpoint, CURLOPT_HEADERFUNCTION, &curl_header_function);
986         curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEHEADER, ps);
987         curl_easy_setopt(ps->recv_endpoint, CURLOPT_READFUNCTION, send_curl_read_callback);
988         curl_easy_setopt(ps->recv_endpoint, CURLOPT_READDATA, ps);
989         curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEFUNCTION, send_curl_write_callback);
990         curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEDATA, ps);
991         curl_easy_setopt(ps->recv_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
992         curl_easy_setopt(ps->recv_endpoint, CURLOPT_PRIVATE, ps);
993         curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
994         curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
995
996         mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint);
997         if (mret != CURLM_OK)
998         {
999           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1000                       _("%s failed at %s:%d: `%s'\n"),
1001                       "curl_multi_add_handle", __FILE__, __LINE__,
1002                       curl_multi_strerror (mret));
1003           return -1;
1004         }
1005
1006         if (ps->msgtok != NULL)
1007           ps->msgtok = GNUNET_SERVER_mst_create (&curl_write_mst_cb, ps);
1008         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound not connected, initiating connection\n",ps);
1009       }
1010     }
1011
1012     /* Check if session is connected to send data, otherwise connect to peer */
1013     if ((ps->send_connected == GNUNET_YES) && (ps->send_endpoint!= NULL))
1014     {
1015       if (ps->send_connected == GNUNET_NO)
1016       {
1017         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound active, enqueueing message\n",ps);
1018         return bytes_sent;
1019       }
1020       if (ps->send_active == GNUNET_NO)
1021       {
1022         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound paused, unpausing existing connection and enqueueing message\n",ps);
1023         curl_easy_pause(ps->send_endpoint,CURLPAUSE_CONT);
1024         ps->send_active=GNUNET_YES;
1025         return bytes_sent;
1026       }
1027     }
1028
1029     /* not connected, initiate connection */
1030     if ( NULL == ps->send_endpoint)
1031       ps->send_endpoint = curl_easy_init();
1032     GNUNET_assert (ps->send_endpoint != NULL);
1033     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound not connected, initiating connection\n",ps);
1034
1035     GNUNET_assert (NULL != ps->pending_msgs_tail);
1036     msg = ps->pending_msgs_tail;
1037
1038   #if DEBUG_CURL
1039     curl_easy_setopt(ps->send_endpoint, CURLOPT_VERBOSE, 1L);
1040   #endif
1041     curl_easy_setopt(ps->send_endpoint, CURLOPT_URL, ps->url);
1042     curl_easy_setopt(ps->send_endpoint, CURLOPT_PUT, 1L);
1043     curl_easy_setopt(ps->send_endpoint, CURLOPT_READFUNCTION, send_curl_read_callback);
1044     curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
1045     curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEFUNCTION, send_curl_write_callback);
1046     curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
1047     curl_easy_setopt(ps->send_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
1048     curl_easy_setopt(ps->send_endpoint, CURLOPT_PRIVATE, ps);
1049     curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1050     curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1051
1052     mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint);
1053     if (mret != CURLM_OK)
1054     {
1055       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1056                   _("%s failed at %s:%d: `%s'\n"),
1057                   "curl_multi_add_handle", __FILE__, __LINE__,
1058                   curl_multi_strerror (mret));
1059       return -1;
1060     }
1061     ps->send_connected = GNUNET_YES;
1062     bytes_sent = send_schedule (plugin, NULL);
1063     return bytes_sent;
1064   }
1065   if (ps->direction == INBOUND)
1066   {
1067     GNUNET_assert (NULL != ps->pending_msgs_tail);
1068     msg = ps->pending_msgs_tail;
1069     if ((ps->recv_connected==GNUNET_YES) && (ps->recv_connected==GNUNET_YES))
1070         bytes_sent = msg->size;
1071     return bytes_sent;
1072   }
1073   return 0;
1074 }
1075
1076 static void send_execute (void *cls,
1077              const struct GNUNET_SCHEDULER_TaskContext *tc)
1078 {
1079   struct Plugin *plugin = cls;
1080   static unsigned int handles_last_run;
1081   int running;
1082   struct CURLMsg *msg;
1083   CURLMcode mret;
1084   struct HTTP_Session *ps = NULL;
1085   struct HTTP_PeerContext *pc = NULL;
1086   struct HTTP_Message * cur_msg = NULL;
1087   long http_result;
1088
1089   GNUNET_assert(cls !=NULL);
1090   plugin->http_server_task_send = GNUNET_SCHEDULER_NO_TASK;
1091   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1092     return;
1093
1094   do
1095     {
1096       running = 0;
1097       mret = curl_multi_perform (plugin->multi_handle, &running);
1098       if (running < handles_last_run)
1099         {
1100           do
1101             {
1102
1103               msg = curl_multi_info_read (plugin->multi_handle, &running);
1104               if (msg == NULL)
1105                 break;
1106               /* get session for affected curl handle */
1107               GNUNET_assert ( msg->easy_handle != NULL );
1108               curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char *) &ps);
1109               GNUNET_assert ( ps != NULL );
1110               pc = ps->peercontext;
1111               GNUNET_assert ( pc != NULL );
1112               switch (msg->msg)
1113                 {
1114
1115                 case CURLMSG_DONE:
1116                   if ( (msg->data.result != CURLE_OK) &&
1117                        (msg->data.result != CURLE_GOT_NOTHING) )
1118                   {
1119                     /* sending msg failed*/
1120                     if (msg->easy_handle == ps->send_endpoint)
1121                     {
1122                       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1123                                  _("Connection %X: HTTP PUT to peer `%s' (`%s') failed: `%s' `%s'\n"),
1124                                  ps,
1125                                  GNUNET_i2s(&pc->identity),
1126                                  http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1127                                  "curl_multi_perform",
1128                                  curl_easy_strerror (msg->data.result));
1129
1130                       ps->send_connected = GNUNET_NO;
1131                       curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
1132                       curl_easy_cleanup(ps->send_endpoint);
1133                       ps->send_endpoint=NULL;
1134                       cur_msg = ps->pending_msgs_tail;
1135                       if (( NULL != cur_msg) && ( NULL != cur_msg->transmit_cont))
1136                         cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
1137                     }
1138                     /* GET connection failed */
1139                     if (msg->easy_handle == ps->recv_endpoint)
1140                     {
1141                       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1142                            _("Connection %X: HTTP GET to peer `%s' (`%s') failed: `%s' `%s'\n"),
1143                            ps,
1144                            GNUNET_i2s(&pc->identity),
1145                            http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1146                            "curl_multi_perform",
1147                            curl_easy_strerror (msg->data.result));
1148                       ps->recv_connected = GNUNET_NO;
1149                       curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
1150                       curl_easy_cleanup(ps->recv_endpoint);
1151                       ps->recv_endpoint=NULL;
1152                     }
1153                   }
1154                   else
1155                   {
1156                     if (msg->easy_handle == ps->send_endpoint)
1157                     {
1158                       GNUNET_assert (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_result));
1159                       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160                                   "Connection %X: HTTP PUT connection to peer `%s' (`%s') was closed with HTTP code %u\n",
1161                                    ps,
1162                                    GNUNET_i2s(&pc->identity),
1163                                    http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1164                                    http_result);
1165
1166                       /* Calling transmit continuation  */
1167                       cur_msg = ps->pending_msgs_tail;
1168                       if (( NULL != cur_msg) && (NULL != cur_msg->transmit_cont))
1169                       {
1170                         /* HTTP 1xx : Last message before here was informational */
1171                         if ((http_result >=100) && (http_result < 200))
1172                           cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
1173                         /* HTTP 2xx: successful operations */
1174                         if ((http_result >=200) && (http_result < 300))
1175                           cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
1176                         /* HTTP 3xx..5xx: error */
1177                         if ((http_result >=300) && (http_result < 600))
1178                           cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
1179                       }
1180                       ps->send_connected = GNUNET_NO;
1181                       curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
1182                       curl_easy_cleanup(ps->send_endpoint);
1183                       ps->send_endpoint =NULL;
1184                     }
1185                     if (msg->easy_handle == ps->recv_endpoint)
1186                     {
1187                       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1188                                   "Connection %X: HTTP GET connection to peer `%s' (`%s') was closed with HTTP code %u\n",
1189                                    ps,
1190                                    GNUNET_i2s(&pc->identity),
1191                                    http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1192                                    http_result);
1193
1194                       ps->recv_connected = GNUNET_NO;
1195                       curl_multi_remove_handle(plugin->multi_handle,msg->easy_handle);
1196                       curl_easy_cleanup(ps->recv_endpoint);
1197                       ps->recv_endpoint=NULL;
1198                     }
1199                   }
1200                   if (ps->pending_msgs_tail != NULL)
1201                   {
1202                     if (ps->pending_msgs_tail->pos>0)
1203                       remove_http_message(ps, ps->pending_msgs_tail);
1204                   }
1205                   return;
1206                 default:
1207                   break;
1208                 }
1209
1210             }
1211           while ( (running > 0) );
1212         }
1213       handles_last_run = running;
1214     }
1215   while (mret == CURLM_CALL_MULTI_PERFORM);
1216   send_schedule(plugin, cls);
1217 }
1218
1219
1220 /**
1221  * Function setting up file descriptors and scheduling task to run
1222  * @param ses session to send data to
1223  * @return bytes sent to peer
1224  */
1225 static size_t send_schedule(void *cls, struct Session* ses )
1226 {
1227   struct Plugin *plugin = cls;
1228   fd_set rs;
1229   fd_set ws;
1230   fd_set es;
1231   int max;
1232   struct GNUNET_NETWORK_FDSet *grs;
1233   struct GNUNET_NETWORK_FDSet *gws;
1234   long to;
1235   CURLMcode mret;
1236
1237   GNUNET_assert(cls !=NULL);
1238   max = -1;
1239   FD_ZERO (&rs);
1240   FD_ZERO (&ws);
1241   FD_ZERO (&es);
1242   mret = curl_multi_fdset (plugin->multi_handle, &rs, &ws, &es, &max);
1243   if (mret != CURLM_OK)
1244     {
1245       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1246                   _("%s failed at %s:%d: `%s'\n"),
1247                   "curl_multi_fdset", __FILE__, __LINE__,
1248                   curl_multi_strerror (mret));
1249       return -1;
1250     }
1251   mret = curl_multi_timeout (plugin->multi_handle, &to);
1252   if (mret != CURLM_OK)
1253     {
1254       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1255                   _("%s failed at %s:%d: `%s'\n"),
1256                   "curl_multi_timeout", __FILE__, __LINE__,
1257                   curl_multi_strerror (mret));
1258       return -1;
1259     }
1260
1261   grs = GNUNET_NETWORK_fdset_create ();
1262   gws = GNUNET_NETWORK_fdset_create ();
1263   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
1264   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
1265   plugin->http_server_task_send = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1266                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1267                                    GNUNET_SCHEDULER_NO_TASK,
1268                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
1269                                    grs,
1270                                    gws,
1271                                    &send_execute,
1272                                    plugin);
1273   GNUNET_NETWORK_fdset_destroy (gws);
1274   GNUNET_NETWORK_fdset_destroy (grs);
1275
1276   /* FIXME: return bytes REALLY sent */
1277   return 0;
1278 }
1279
1280
1281 /**
1282  * Function that can be used by the transport service to transmit
1283  * a message using the plugin.   Note that in the case of a
1284  * peer disconnecting, the continuation MUST be called
1285  * prior to the disconnect notification itself.  This function
1286  * will be called with this peer's HELLO message to initiate
1287  * a fresh connection to another peer.
1288  *
1289  * @param cls closure
1290  * @param target who should receive this message
1291  * @param msgbuf the message to transmit
1292  * @param msgbuf_size number of bytes in 'msgbuf'
1293  * @param priority how important is the message (most plugins will
1294  *                 ignore message priority and just FIFO)
1295  * @param timeout how long to wait at most for the transmission (does not
1296  *                require plugins to discard the message after the timeout,
1297  *                just advisory for the desired delay; most plugins will ignore
1298  *                this as well)
1299  * @param session which session must be used (or NULL for "any")
1300  * @param addr the address to use (can be NULL if the plugin
1301  *                is "on its own" (i.e. re-use existing TCP connection))
1302  * @param addrlen length of the address in bytes
1303  * @param force_address GNUNET_YES if the plugin MUST use the given address,
1304  *                GNUNET_NO means the plugin may use any other address and
1305  *                GNUNET_SYSERR means that only reliable existing
1306  *                bi-directional connections should be used (regardless
1307  *                of address)
1308  * @param cont continuation to call once the message has
1309  *        been transmitted (or if the transport is ready
1310  *        for the next transmission call; or if the
1311  *        peer disconnected...); can be NULL
1312  * @param cont_cls closure for cont
1313  * @return number of bytes used (on the physical network, with overheads);
1314  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1315  *         and does NOT mean that the message was not transmitted (DV)
1316  */
1317 static ssize_t
1318 http_plugin_send (void *cls,
1319                   const struct GNUNET_PeerIdentity *target,
1320                   const char *msgbuf,
1321                   size_t msgbuf_size,
1322                   unsigned int priority,
1323                   struct GNUNET_TIME_Relative to,
1324                   struct Session *session,
1325                   const void *addr,
1326                   size_t addrlen,
1327                   int force_address,
1328                   GNUNET_TRANSPORT_TransmitContinuation cont,
1329                   void *cont_cls)
1330 {
1331   struct Plugin *plugin = cls;
1332   struct HTTP_Message *msg;
1333
1334   struct HTTP_PeerContext * pc;
1335   struct HTTP_Session * ps;
1336
1337   GNUNET_assert(cls !=NULL);
1338   GNUNET_assert ((addr!=NULL) && (addrlen != 0));
1339
1340   pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
1341   /* Peer unknown */
1342   if (pc==NULL)
1343   {
1344     pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
1345     pc->plugin = plugin;
1346     memcpy(&pc->identity, target, sizeof(struct GNUNET_PeerIdentity));
1347     GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1348   }
1349   ps = get_HTTP_Session(plugin, pc, addr, addrlen);
1350   /* session not existing, but address forced -> creating new session */
1351   if ((ps==NULL) && (force_address == GNUNET_YES))
1352   {
1353     ps = GNUNET_malloc(sizeof (struct HTTP_Session));
1354     ps->addr = GNUNET_malloc(addrlen);
1355     memcpy(ps->addr,addr,addrlen);
1356     ps->addrlen = addrlen;
1357     ps->direction=OUTBOUND;
1358     ps->recv_connected = GNUNET_NO;
1359     ps->send_connected = GNUNET_NO;
1360     ps->pending_msgs_head = NULL;
1361     ps->pending_msgs_tail = NULL;
1362     ps->peercontext=pc;
1363     ps->url = create_url (plugin, ps->addr, ps->addrlen);
1364     GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
1365   }
1366   /* session not existing, address not forced -> looking for other session */
1367   if ((ps==NULL) && (force_address == GNUNET_NO))
1368   {
1369     /* FIXME: CREATING SESSION, SHOULD CHOOSE EXISTING */
1370     ps = GNUNET_malloc(sizeof (struct HTTP_Session));
1371     ps->addr = GNUNET_malloc(addrlen);
1372     memcpy(ps->addr,addr,addrlen);
1373     ps->addrlen = addrlen;
1374     ps->direction=OUTBOUND;
1375     ps->recv_connected = GNUNET_NO;
1376     ps->send_connected = GNUNET_NO;
1377     ps->pending_msgs_head = NULL;
1378     ps->pending_msgs_tail = NULL;
1379     ps->peercontext=pc;
1380     ps->url = create_url (plugin, ps->addr, ps->addrlen);
1381     GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
1382   }
1383   if ((ps==NULL) && (force_address == GNUNET_SYSERR))
1384   {
1385     /* FIXME: CREATING SESSION, SHOULD CHOOSE EXISTING */
1386     ps = GNUNET_malloc(sizeof (struct HTTP_Session));
1387     ps->addr = GNUNET_malloc(addrlen);
1388     memcpy(ps->addr,addr,addrlen);
1389     ps->addrlen = addrlen;
1390     ps->direction=OUTBOUND;
1391     ps->recv_connected = GNUNET_NO;
1392     ps->send_connected = GNUNET_NO;
1393     ps->pending_msgs_head = NULL;
1394     ps->pending_msgs_tail = NULL;
1395     ps->peercontext=pc;
1396     ps->url = create_url (plugin, ps->addr, ps->addrlen);
1397     GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
1398   }
1399
1400   char * force = GNUNET_malloc(30);
1401   if (force_address == GNUNET_YES)
1402     strcpy(force,"forced addr.");
1403   if (force_address == GNUNET_NO)
1404     strcpy(force,"any addr.");
1405   if (force_address == GNUNET_SYSERR)
1406     strcpy(force,"reliable bi-direc. address addr.");
1407   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to `%s' %s (%s), session: %X\n",
1408                                       msgbuf_size,
1409                                       GNUNET_i2s(&pc->identity),
1410                                       force,
1411                                       http_plugin_address_to_string(NULL, addr, addrlen),
1412                                       ps);
1413
1414   GNUNET_free(force);
1415   /* create msg */
1416   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
1417   msg->next = NULL;
1418   msg->size = msgbuf_size;
1419   msg->pos = 0;
1420   msg->buf = (char *) &msg[1];
1421   msg->transmit_cont = cont;
1422   msg->transmit_cont_cls = cont_cls;
1423   memcpy (msg->buf,msgbuf, msgbuf_size);
1424   GNUNET_CONTAINER_DLL_insert(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
1425
1426   return send_check_connections (plugin, session, ps);
1427 }
1428
1429
1430
1431 /**
1432  * Function that can be used to force the plugin to disconnect
1433  * from the given peer and cancel all previous transmissions
1434  * (and their continuationc).
1435  *
1436  * @param cls closure
1437  * @param target peer from which to disconnect
1438  */
1439 static void
1440 http_plugin_disconnect (void *cls,
1441                             const struct GNUNET_PeerIdentity *target)
1442 {
1443
1444   struct Plugin *plugin = cls;
1445   struct HTTP_PeerContext *pc = NULL;
1446   struct HTTP_Session *ps = NULL;
1447
1448   pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
1449   if (pc==NULL)
1450     return;
1451
1452   ps = pc->head;
1453
1454   while (ps!=NULL)
1455   {
1456     if (ps->direction==OUTBOUND)
1457     {
1458       if (ps->send_endpoint!=NULL)
1459       {
1460         curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1461         curl_easy_cleanup(ps->send_endpoint);
1462         ps->send_endpoint=NULL;
1463       }
1464       if (ps->recv_endpoint!=NULL)
1465       {
1466        curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1467        curl_easy_cleanup(ps->recv_endpoint);
1468        ps->recv_endpoint=NULL;
1469       }
1470     }
1471     if (ps->direction==INBOUND)
1472     {
1473
1474     }
1475     while (ps->pending_msgs_head!=NULL)
1476     {
1477       remove_http_message(ps, ps->pending_msgs_head);
1478     }
1479     ps->recv_connected = GNUNET_NO;
1480     ps->recv_active = GNUNET_NO;
1481     ps->send_connected = GNUNET_NO;
1482     ps->send_active = GNUNET_NO;
1483     ps=ps->next;
1484   }
1485
1486 #if 0
1487   /* get peercontext from hashmap */
1488   cs = session_get(plugin, target);
1489   con = cs->outbound_connections_head;
1490
1491   while (con!=NULL)
1492   {
1493     if (con->put_curl_handle!=NULL)
1494       curl_easy_cleanup(con->put_curl_handle);
1495     con->put_curl_handle=NULL;
1496     con->put_connected = GNUNET_NO;
1497     while (con->pending_msgs_head!=NULL)
1498     {
1499       //remove_http_message(con, con->pending_msgs_head);
1500     }
1501     con=con->next;
1502   }
1503 #endif
1504 }
1505
1506
1507 /**
1508  * Convert the transports address to a nice, human-readable
1509  * format.
1510  *
1511  * @param cls closure
1512  * @param type name of the transport that generated the address
1513  * @param addr one of the addresses of the host, NULL for the last address
1514  *        the specific address format depends on the transport
1515  * @param addrlen length of the address
1516  * @param numeric should (IP) addresses be displayed in numeric form?
1517  * @param timeout after how long should we give up?
1518  * @param asc function to call on each string
1519  * @param asc_cls closure for asc
1520  */
1521 static void
1522 http_plugin_address_pretty_printer (void *cls,
1523                                         const char *type,
1524                                         const void *addr,
1525                                         size_t addrlen,
1526                                         int numeric,
1527                                         struct GNUNET_TIME_Relative timeout,
1528                                         GNUNET_TRANSPORT_AddressStringCallback
1529                                         asc, void *asc_cls)
1530 {
1531   const struct IPv4HttpAddress *t4;
1532   const struct IPv6HttpAddress *t6;
1533   struct sockaddr_in a4;
1534   struct sockaddr_in6 a6;
1535   char * address;
1536   char * ret;
1537   unsigned int port;
1538   unsigned int res;
1539
1540   GNUNET_assert(cls !=NULL);
1541   if (addrlen == sizeof (struct IPv6HttpAddress))
1542   {
1543     address = GNUNET_malloc (INET6_ADDRSTRLEN);
1544     t6 = addr;
1545     a6.sin6_addr = t6->ipv6_addr;
1546     inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
1547     port = ntohs(t6->u6_port);
1548   }
1549   else if (addrlen == sizeof (struct IPv4HttpAddress))
1550   {
1551     address = GNUNET_malloc (INET_ADDRSTRLEN);
1552     t4 = addr;
1553     a4.sin_addr.s_addr =  t4->ipv4_addr;
1554     inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
1555     port = ntohs(t4->u_port);
1556   }
1557   else
1558   {
1559     /* invalid address */
1560     GNUNET_break_op (0);
1561     asc (asc_cls, NULL);
1562     return;
1563   }
1564   res = GNUNET_asprintf(&ret,"http://%s:%u/",address,port);
1565   GNUNET_free (address);
1566   GNUNET_assert(res != 0);
1567
1568   asc (asc_cls, ret);
1569 }
1570
1571
1572
1573 /**
1574  * Another peer has suggested an address for this
1575  * peer and transport plugin.  Check that this could be a valid
1576  * address.  If so, consider adding it to the list
1577  * of addresses.
1578  *
1579  * @param cls closure
1580  * @param addr pointer to the address
1581  * @param addrlen length of addr
1582  * @return GNUNET_OK if this is a plausible address for this peer
1583  *         and transport
1584  */
1585 static int
1586 http_plugin_address_suggested (void *cls,
1587                                const void *addr, size_t addrlen)
1588 {
1589   struct Plugin *plugin = cls;
1590   struct IPv4HttpAddress *v4;
1591   struct IPv6HttpAddress *v6;
1592   unsigned int port;
1593
1594   GNUNET_assert(cls !=NULL);
1595   if ((addrlen != sizeof (struct IPv4HttpAddress)) &&
1596       (addrlen != sizeof (struct IPv6HttpAddress)))
1597     {
1598       return GNUNET_SYSERR;
1599     }
1600   if (addrlen == sizeof (struct IPv4HttpAddress))
1601     {
1602       v4 = (struct IPv4HttpAddress *) addr;
1603       if (INADDR_LOOPBACK == ntohl(v4->ipv4_addr))
1604       {
1605         return GNUNET_SYSERR;
1606       }
1607       port = ntohs (v4->u_port);
1608       if (port != plugin->port_inbound)
1609       {
1610         return GNUNET_SYSERR;
1611       }
1612     }
1613   else
1614     {
1615       v6 = (struct IPv6HttpAddress *) addr;
1616       if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1617         {
1618           return GNUNET_SYSERR;
1619         }
1620       port = ntohs (v6->u6_port);
1621       if (port != plugin->port_inbound)
1622       {
1623         return GNUNET_SYSERR;
1624       }
1625     }
1626   return GNUNET_OK;
1627 }
1628
1629
1630 /**
1631  * Function called for a quick conversion of the binary address to
1632  * a numeric address.  Note that the caller must not free the
1633  * address and that the next call to this function is allowed
1634  * to override the address again.
1635  *
1636  * @param cls closure
1637  * @param addr binary address
1638  * @param addrlen length of the address
1639  * @return string representing the same address
1640  */
1641 static const char*
1642 http_plugin_address_to_string (void *cls,
1643                                    const void *addr,
1644                                    size_t addrlen)
1645 {
1646   const struct IPv4HttpAddress *t4;
1647   const struct IPv6HttpAddress *t6;
1648   struct sockaddr_in a4;
1649   struct sockaddr_in6 a6;
1650   char * address;
1651   char * ret;
1652   uint16_t port;
1653   unsigned int res;
1654
1655   if (addrlen == sizeof (struct IPv6HttpAddress))
1656     {
1657       address = GNUNET_malloc (INET6_ADDRSTRLEN);
1658       t6 = addr;
1659       a6.sin6_addr = t6->ipv6_addr;
1660       inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
1661       port = ntohs(t6->u6_port);
1662     }
1663   else if (addrlen == sizeof (struct IPv4HttpAddress))
1664     {
1665       address = GNUNET_malloc (INET_ADDRSTRLEN);
1666       t4 = addr;
1667       a4.sin_addr.s_addr =  t4->ipv4_addr;
1668       inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
1669       port = ntohs(t4->u_port);
1670     }
1671   else
1672     {
1673       /* invalid address */
1674       return NULL;
1675     }
1676   res = GNUNET_asprintf(&ret,"%s:%u",address,port);
1677   GNUNET_free (address);
1678   GNUNET_assert(res != 0);
1679   return ret;
1680 }
1681
1682 /**
1683  * Add the IP of our network interface to the list of
1684  * our external IP addresses.
1685  *
1686  * @param cls the 'struct Plugin*'
1687  * @param name name of the interface
1688  * @param isDefault do we think this may be our default interface
1689  * @param addr address of the interface
1690  * @param addrlen number of bytes in addr
1691  * @return GNUNET_OK to continue iterating
1692  */
1693 static int
1694 process_interfaces (void *cls,
1695                     const char *name,
1696                     int isDefault,
1697                     const struct sockaddr *addr, socklen_t addrlen)
1698 {
1699   struct Plugin *plugin = cls;
1700   struct IPv4HttpAddress * t4;
1701   struct IPv6HttpAddress * t6;
1702   int af;
1703
1704   GNUNET_assert(cls !=NULL);
1705   af = addr->sa_family;
1706   if (af == AF_INET)
1707     {
1708       t4 = GNUNET_malloc(sizeof(struct IPv4HttpAddress));
1709       if (INADDR_LOOPBACK == ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr))
1710       {
1711         /* skip loopback addresses */
1712         return GNUNET_OK;
1713       }
1714       t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1715       t4->u_port = htons (plugin->port_inbound);
1716       plugin->env->notify_address(plugin->env->cls,"http",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
1717
1718     }
1719   else if (af == AF_INET6)
1720     {
1721       t6 = GNUNET_malloc(sizeof(struct IPv6HttpAddress));
1722       if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1723         {
1724           /* skip link local addresses */
1725           return GNUNET_OK;
1726         }
1727       if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))
1728         {
1729           /* skip loopback addresses */
1730           return GNUNET_OK;
1731         }
1732       memcpy (&t6->ipv6_addr,
1733               &((struct sockaddr_in6 *) addr)->sin6_addr,
1734               sizeof (struct in6_addr));
1735       t6->u6_port = htons (plugin->port_inbound);
1736       plugin->env->notify_address(plugin->env->cls,"http",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
1737     }
1738   return GNUNET_OK;
1739 }
1740
1741 int peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value)
1742 {
1743   struct HTTP_PeerContext * pc = value;
1744   struct HTTP_Session * ps = pc->head;
1745   struct HTTP_Session * tmp = NULL;
1746   struct HTTP_Message * msg = NULL;
1747   struct HTTP_Message * msg_tmp = NULL;
1748
1749   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity));
1750
1751   while (ps!=NULL)
1752   {
1753     tmp = ps->next;
1754
1755     GNUNET_free(ps->addr);
1756     GNUNET_free(ps->url);
1757     if (ps->msgtok != NULL)
1758       GNUNET_SERVER_mst_destroy (ps->msgtok);
1759
1760     msg = ps->pending_msgs_head;
1761     while (msg!=NULL)
1762     {
1763       msg_tmp = msg->next;
1764       GNUNET_free(msg);
1765       msg = msg_tmp;
1766     }
1767     if (ps->direction==OUTBOUND)
1768     {
1769       if (ps->send_endpoint!=NULL)
1770         curl_easy_cleanup(ps->send_endpoint);
1771       if (ps->recv_endpoint!=NULL)
1772         curl_easy_cleanup(ps->recv_endpoint);
1773     }
1774
1775     GNUNET_free(ps);
1776     ps=tmp;
1777   }
1778   GNUNET_free(pc);
1779   return GNUNET_YES;
1780 }
1781
1782
1783 /**
1784  * Exit point from the plugin.
1785  */
1786 void *
1787 libgnunet_plugin_transport_http_done (void *cls)
1788 {
1789   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1790   struct Plugin *plugin = api->cls;
1791   CURLMcode mret;
1792
1793   GNUNET_assert(cls !=NULL);
1794
1795   if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1796   {
1797     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
1798     plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
1799   }
1800
1801   if ( plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1802   {
1803     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
1804     plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1805   }
1806
1807   if ( plugin->http_server_task_send != GNUNET_SCHEDULER_NO_TASK)
1808   {
1809     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_send);
1810     plugin->http_server_task_send = GNUNET_SCHEDULER_NO_TASK;
1811   }
1812
1813   if (plugin->http_server_daemon_v4 != NULL)
1814   {
1815     MHD_stop_daemon (plugin->http_server_daemon_v4);
1816     plugin->http_server_daemon_v4 = NULL;
1817   }
1818   if (plugin->http_server_daemon_v6 != NULL)
1819   {
1820     MHD_stop_daemon (plugin->http_server_daemon_v6);
1821     plugin->http_server_daemon_v6 = NULL;
1822   }
1823
1824   /* free all peer information */
1825   GNUNET_CONTAINER_multihashmap_iterate (plugin->peers,
1826                                          &peer_context_Iterator,
1827                                          NULL);
1828   GNUNET_CONTAINER_multihashmap_destroy (plugin->peers);
1829
1830   mret = curl_multi_cleanup(plugin->multi_handle);
1831   if ( CURLM_OK != mret)
1832     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed");
1833
1834   GNUNET_free (plugin);
1835   GNUNET_free (api);
1836   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unload http plugin complete...\n");
1837   return NULL;
1838 }
1839
1840
1841 /**
1842  * Entry point for the plugin.
1843  */
1844 void *
1845 libgnunet_plugin_transport_http_init (void *cls)
1846 {
1847   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1848   struct Plugin *plugin;
1849   struct GNUNET_TRANSPORT_PluginFunctions *api;
1850   struct GNUNET_TIME_Relative gn_timeout;
1851   long long unsigned int port;
1852
1853   GNUNET_assert(cls !=NULL);
1854   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting http plugin...\n");
1855
1856   plugin = GNUNET_malloc (sizeof (struct Plugin));
1857   plugin->env = env;
1858   plugin->peers = NULL;
1859
1860   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1861   api->cls = plugin;
1862   api->send = &http_plugin_send;
1863   api->disconnect = &http_plugin_disconnect;
1864   api->address_pretty_printer = &http_plugin_address_pretty_printer;
1865   api->check_address = &http_plugin_address_suggested;
1866   api->address_to_string = &http_plugin_address_to_string;
1867
1868   /* Hashing our identity to use it in URLs */
1869   GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &plugin->my_ascii_hash_ident);
1870
1871   /* Reading port number from config file */
1872   if ((GNUNET_OK !=
1873        GNUNET_CONFIGURATION_get_value_number (env->cfg,
1874                                               "transport-http",
1875                                               "PORT",
1876                                               &port)) ||
1877       (port > 65535) )
1878     {
1879       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1880                        "http",
1881                        _
1882                        ("Require valid port number for transport plugin `%s' in configuration!\n"),
1883                        "transport-http");
1884       libgnunet_plugin_transport_http_done (api);
1885       return NULL;
1886     }
1887   GNUNET_assert ((port > 0) && (port <= 65535));
1888   plugin->port_inbound = port;
1889   gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
1890   if ((plugin->http_server_daemon_v4 == NULL) && (plugin->http_server_daemon_v6 == NULL) && (port != 0))
1891     {
1892     plugin->http_server_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
1893                                        port,
1894                                        &acceptPolicyCallback,
1895                                        plugin , &accessHandlerCallback, plugin,
1896                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
1897                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1898                                        MHD_OPTION_CONNECTION_TIMEOUT, (gn_timeout.value / 1000),
1899                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
1900                                        MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
1901                                        MHD_OPTION_END);
1902     plugin->http_server_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
1903                                        port,
1904                                        &acceptPolicyCallback,
1905                                        plugin , &accessHandlerCallback, plugin,
1906                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
1907                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1908                                        MHD_OPTION_CONNECTION_TIMEOUT, (gn_timeout.value / 1000),
1909                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
1910                                        MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
1911                                        MHD_OPTION_END);
1912     }
1913   if (plugin->http_server_daemon_v4 != NULL)
1914     plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
1915   if (plugin->http_server_daemon_v6 != NULL)
1916     plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
1917
1918   if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1919     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 on port %u\n",port);
1920   else if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1921     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 on port %u\n",port);
1922   else
1923   {
1924     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No MHD was started, transport plugin not functional!\n");
1925     libgnunet_plugin_transport_http_done (api);
1926     return NULL;
1927   }
1928
1929   /* Initializing cURL */
1930   curl_global_init(CURL_GLOBAL_ALL);
1931   plugin->multi_handle = curl_multi_init();
1932
1933   if ( NULL == plugin->multi_handle )
1934   {
1935     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1936                      "http",
1937                      _("Could not initialize curl multi handle, failed to start http plugin!\n"),
1938                      "transport-http");
1939     libgnunet_plugin_transport_http_done (api);
1940     return NULL;
1941   }
1942
1943   plugin->peers = GNUNET_CONTAINER_multihashmap_create (10);
1944   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
1945
1946   return api;
1947 }
1948
1949 /* end of plugin_transport_http.c */