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