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