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