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