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