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