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