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