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