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