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