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