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