fea3bc89e8e73aa76f114446d9f01f3574b85b46
[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 2, 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_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_connection_lib.h"
31 #include "gnunet_server_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 HTTP_CONNECT_TIMEOUT_DBG 10
47
48 /**
49  * Text of the response sent back after the last bytes of a PUT
50  * request have been received (just to formally obey the HTTP
51  * protocol).
52  */
53 #define HTTP_PUT_RESPONSE "Thank you!"
54
55 /**
56  * After how long do we expire an address that we
57  * learned from another peer if it is not reconfirmed
58  * by anyone?
59  */
60 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
61
62 /**
63  * Page returned if request invalid
64  */
65 #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>"
66
67 /**
68  * Timeout for a http connect
69  */
70 #define HTTP_CONNECT_TIMEOUT 30
71
72 /**
73  * Network format for IPv4 addresses.
74  */
75 struct IPv4HttpAddress
76 {
77   /**
78    * IPv4 address, in network byte order.
79    */
80   uint32_t ipv4_addr GNUNET_PACKED;
81
82   /**
83    * Port number, in network byte order.
84    */
85   uint16_t u_port GNUNET_PACKED;
86
87 };
88
89
90 /**
91  * Network format for IPv6 addresses.
92  */
93 struct IPv6HttpAddress
94 {
95   /**
96    * IPv6 address.
97    */
98   struct in6_addr ipv6_addr GNUNET_PACKED;
99
100   /**
101    * Port number, in network byte order.
102    */
103   uint16_t u6_port GNUNET_PACKED;
104
105 };
106
107
108 /**
109  *  Message to send using http
110  */
111 struct HTTP_Message
112 {
113   /**
114    * next pointer for double linked list
115    */
116   struct HTTP_Message * next;
117
118   /**
119    * previous pointer for double linked list
120    */
121   struct HTTP_Message * prev;
122
123   /**
124    * buffer containing data to send
125    */
126   char *buf;
127
128   /**
129    * amount of data already sent
130    */
131   size_t pos;
132
133   /**
134    * buffer length
135    */
136   size_t size;
137   
138   /**
139    * Continuation function to call once the transmission buffer
140    * has again space available.  NULL if there is no
141    * continuation to call.
142    */
143   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
144
145   /**
146    * Closure for transmit_cont.
147    */
148   void *transmit_cont_cls;
149 };
150
151
152 struct HTTP_Connection_out
153 {
154   struct HTTP_Connection_out * next;
155
156   struct HTTP_Connection_out * prev;
157
158   void * addr;
159   size_t addrlen;
160
161   struct HTTP_Message * pending_msgs_head;
162   struct HTTP_Message * pending_msgs_tail;
163
164   char * url;
165   unsigned int put_connected;
166   unsigned int put_send_paused;
167
168   unsigned int get_connected;
169
170   /**
171    * curl handle for sending data using HTTP/PUT
172    * outbound data
173    */
174   CURL *put_curl_handle;
175
176   /**
177    * curl handle for recieving data using HTTP/GET transmission
178    * inbound data
179    */
180   CURL *get_curl_handle;
181
182   struct Session * session;
183 };
184
185 struct HTTP_Connection_in
186 {
187   struct HTTP_Connection_in * next;
188
189   struct HTTP_Connection_in * prev;
190
191   void * addr;
192   size_t addrlen;
193
194   unsigned int connected;
195   unsigned int send_paused;
196
197   struct GNUNET_SERVER_MessageStreamTokenizer * msgtok;
198
199   struct Session * session;
200
201   /**
202    * Is there a HTTP/PUT in progress?
203    */
204   int is_put_in_progress;
205
206   /**
207    * Is the http request invalid?
208    */
209   int is_bad_request;
210 };
211
212
213 /**
214  * Session handle for connections.
215  */
216 struct Session
217 {
218
219   /**
220    * API requirement.
221    */
222   struct SessionHeader header;
223
224   /**
225    * Stored in a linked list.
226    */
227   struct Session *next;
228
229   /**
230    * Pointer to the global plugin struct.
231    */
232   struct Plugin *plugin;
233
234   /**
235    * To whom are we talking to (set to our identity
236    * if we are still waiting for the welcome message)
237    */
238   struct GNUNET_PeerIdentity identity;
239
240   /**
241    * Sender's ip address to distinguish between incoming connections
242    */
243   void * addr_in;
244
245   size_t addr_in_len;
246
247   void * addr_out;
248
249   size_t addr_out_len;
250
251   /**
252    * Did we initiate the connection (GNUNET_YES) or the other peer (GNUNET_NO)?
253    */
254   int is_client;
255
256   /**
257    * At what time did we reset last_received last?
258    */
259   struct GNUNET_TIME_Absolute last_quota_update;
260
261   /**
262    * How many bytes have we received since the "last_quota_update"
263    * timestamp?
264    */
265   uint64_t last_received;
266
267   /**
268    * Number of bytes per ms that this peer is allowed
269    * to send to us.
270    */
271   uint32_t quota;
272
273   /**
274    * Encoded hash
275    */
276   struct GNUNET_CRYPTO_HashAsciiEncoded hash;
277
278   /**
279    * curl handle for outbound transmissions
280    */
281   CURL *curl_handle;
282
283   /**
284    * Message tokenizer for incoming data
285    */
286   //struct GNUNET_SERVER_MessageStreamTokenizer * msgtok;
287
288   struct HTTP_Connection_out *outbound_connections_head;
289   struct HTTP_Connection_out *outbound_connections_tail;
290
291   struct HTTP_Connection_in *inbound_connections_head;
292   struct HTTP_Connection_in *inbound_connections_tail;
293 };
294
295 /**
296  * Encapsulation of all of the state of the plugin.
297  */
298 struct Plugin
299 {
300   /**
301    * Our environment.
302    */
303   struct GNUNET_TRANSPORT_PluginEnvironment *env;
304
305   unsigned int port_inbound;
306
307   /**
308    * Hashmap for all existing sessions.
309    */
310   struct GNUNET_CONTAINER_MultiHashMap *sessions;
311
312   /**
313    * Daemon for listening for new IPv4 connections.
314    */
315   struct MHD_Daemon *http_server_daemon_v4;
316
317   /**
318    * Daemon for listening for new IPv6connections.
319    */
320   struct MHD_Daemon *http_server_daemon_v6;
321
322   /**
323    * Our primary task for http daemon handling IPv4 connections
324    */
325   GNUNET_SCHEDULER_TaskIdentifier http_server_task_v4;
326
327   /**
328    * Our primary task for http daemon handling IPv6 connections
329    */
330   GNUNET_SCHEDULER_TaskIdentifier http_server_task_v6;
331
332   /**
333    * The task sending data
334    */
335   GNUNET_SCHEDULER_TaskIdentifier http_server_task_send;
336
337   /**
338    * cURL Multihandle
339    */
340   CURLM * multi_handle;
341
342   /**
343    * Our ASCII encoded, hashed peer identity
344    * This string is used to distinguish between connections and is added to the urls
345    */
346   struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
347 };
348
349
350 /**
351  * Function called for a quick conversion of the binary address to
352  * a numeric address.  Note that the caller must not free the
353  * address and that the next call to this function is allowed
354  * to override the address again.
355  *
356  * @param cls closure
357  * @param addr binary address
358  * @param addrlen length of the address
359  * @return string representing the same address
360  */
361 static const char*
362 http_plugin_address_to_string (void *cls,
363                                    const void *addr,
364                                    size_t addrlen);
365
366 /**
367  * Create a new session
368  * @param cls plugin as closure
369  * @param addr_in address the peer is using inbound
370  * @param addr_len_in address length
371  * @param addr_out address the peer is using outbound
372  * @param addr_len_out address length
373  * @param peer identity
374  * @return created session object
375  */
376 static struct Session * 
377 create_session (void * cls, 
378                 char * addr_in, 
379                 size_t addrlen_in,
380                 char * addr_out, 
381                 size_t addrlen_out, 
382                 const struct GNUNET_PeerIdentity *peer)
383 {
384   struct Plugin *plugin = cls;
385   struct Session * cs = GNUNET_malloc ( sizeof( struct Session) );
386
387   GNUNET_assert(cls !=NULL);
388   if (addrlen_in != 0)
389   {
390     cs->addr_in = GNUNET_malloc (addrlen_in);
391     cs->addr_in_len = addrlen_in;
392     memcpy(cs->addr_in,addr_in,addrlen_in);
393   }
394
395   if (addrlen_out != 0)
396   {
397     cs->addr_out = GNUNET_malloc (addrlen_out);
398     cs->addr_out_len = addrlen_out;
399     memcpy(cs->addr_out,addr_out,addrlen_out);
400   }
401   cs->plugin = plugin;
402   memcpy(&cs->identity, peer, sizeof (struct GNUNET_PeerIdentity));
403   GNUNET_CRYPTO_hash_to_enc(&cs->identity.hashPubKey,&(cs->hash));
404   cs->outbound_connections_head = NULL;
405   cs->outbound_connections_tail = NULL;
406   return cs;
407 }
408
409 /**
410  * Check if session for this peer is already existing, otherwise create it
411  * @param cls the plugin used
412  * @param p peer to get session for
413  * @return session found or created
414  */
415 static struct Session * session_get (void * cls, const struct GNUNET_PeerIdentity *p)
416 {
417   struct Plugin *plugin = cls;
418   struct Session *cs;
419   unsigned int res;
420
421   cs = GNUNET_CONTAINER_multihashmap_get (plugin->sessions, &p->hashPubKey);
422   if (cs == NULL)
423   {
424     cs = create_session(plugin, NULL, 0, NULL, 0, p);
425     res = GNUNET_CONTAINER_multihashmap_put ( plugin->sessions,
426                                         &cs->identity.hashPubKey,
427                                         cs,
428                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
429     if (res == GNUNET_OK)
430       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431                   "New Session `%s' inserted\n", GNUNET_i2s(p));
432   }
433   return cs;
434 }
435
436 static char * create_url(void * cls, const void * addr, size_t addrlen)
437 {
438   struct Plugin *plugin = cls;
439   char *url = NULL;
440
441   GNUNET_assert ((addr!=NULL) && (addrlen != 0));
442   GNUNET_asprintf(&url,
443                   "http://%s/%s",
444                   http_plugin_address_to_string(NULL, addr, addrlen),
445                   (char *) (&plugin->my_ascii_hash_ident));
446
447   return url;
448 }
449
450 /**
451  * Check if session already knows this address for a outbound connection to this peer
452  * If address not in session, add it to the session
453  * @param cls the plugin used
454  * @param cs the session
455  * @param addr address
456  * @param addr_len address length
457  * @return the found or created address
458  */
459 static struct HTTP_Connection_out * session_check_outbound_address (void * cls, struct Session *cs, const void * addr, size_t addr_len)
460 {
461   struct Plugin *plugin = cls;
462   struct HTTP_Connection_out * cc = cs->outbound_connections_head;
463   struct HTTP_Connection_out * con = NULL;
464
465   GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
466
467   while (cc!=NULL)
468   {
469     if (addr_len == cc->addrlen)
470     {
471       if (0 == memcmp(cc->addr, addr, addr_len))
472       {
473         con = cc;
474         break;
475       }
476     }
477     cc=cc->next;
478   }
479
480   if (con==NULL)
481   {
482     con = GNUNET_malloc(sizeof(struct HTTP_Connection_out) + addr_len);
483     con->addrlen = addr_len;
484     con->addr=&con[1];
485     con->url=create_url(plugin, addr, addr_len);
486     con->put_curl_handle = NULL;
487     con->put_connected = GNUNET_NO;
488     con->get_curl_handle = NULL;
489     con->get_connected = GNUNET_NO;
490     con->session = cs;
491     memcpy(con->addr, addr, addr_len);
492     GNUNET_CONTAINER_DLL_insert(cs->outbound_connections_head,cs->outbound_connections_tail,con);
493     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Created new connection %X to peer `%s'\n",con,GNUNET_i2s(&cs->identity));
494   }
495   return con;
496 }
497
498
499 /**
500  * Check if session already knows this address for a inbound connection to this peer
501  * If address not in session, add it to the session
502  * @param cls not needed, can be NULL
503  * @param cs the session
504  * @param addr address
505  * @param addr_len address length
506  * @return the found or created address
507  */
508 static struct HTTP_Connection_in * session_check_inbound_address (void * cls, struct Session *cs, const void * addr, size_t addr_len)
509 {
510   struct HTTP_Connection_in * cc = cs->inbound_connections_head;
511   struct HTTP_Connection_in * con = NULL;
512
513   GNUNET_assert((addr_len == sizeof (struct IPv4HttpAddress)) || (addr_len == sizeof (struct IPv6HttpAddress)));
514
515   while (cc!=NULL)
516   {
517     if (addr_len == cc->addrlen)
518     {
519       if (0 == memcmp(cc->addr, addr, addr_len))
520       {
521         con = cc;
522         break;
523       }
524     }
525     cc=cc->next;
526   }
527
528
529   if (con==NULL)
530   {
531     con = GNUNET_malloc(sizeof(struct HTTP_Connection_in) + addr_len);
532     con->addrlen = addr_len;
533     con->addr=&con[1];
534     con->connected = GNUNET_NO;
535     con->session = cs;
536     memcpy(con->addr, addr, addr_len);
537     GNUNET_CONTAINER_DLL_insert(cs->inbound_connections_head,cs->inbound_connections_tail,con);
538   }
539
540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X for inbound address %s (%s) was found\n",
541               con,
542               GNUNET_i2s(&cs->identity),
543               http_plugin_address_to_string(NULL,con->addr,con->addrlen));
544   return con;
545 }
546
547
548 /**
549  * Callback called by MHD when a connection is terminated
550  */
551 static void requestCompletedCallback (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
552 {
553   struct HTTP_Connection_in * con;
554
555   con = *httpSessionCache;
556   if (con == NULL)
557     return;
558   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection from peer `%s' was terminated\n",GNUNET_i2s(&con->session->identity));
559   /* session set to inactive */
560   con->is_put_in_progress = GNUNET_NO;
561   con->is_bad_request = GNUNET_NO;
562 }
563
564 static void messageTokenizerCallback (void *cls,
565                                       void *client,
566                                       const struct GNUNET_MessageHeader *message)
567 {
568   struct HTTP_Connection_in * con = cls;
569   GNUNET_assert(con != NULL);
570
571   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
572               "Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
573               ntohs(message->type),
574               ntohs(message->size),
575               GNUNET_i2s(&(con->session->identity)),http_plugin_address_to_string(NULL,con->addr,con->addrlen));
576
577   con->session->plugin->env->receive (con->session->plugin->env->cls,
578                             &con->session->identity,
579                             message, 1, con->session,
580                             NULL,
581                             0);
582 }
583
584 /**
585  * Check if ip is allowed to connect.
586  */
587 static int
588 acceptPolicyCallback (void *cls,
589                       const struct sockaddr *addr, socklen_t addr_len)
590 {
591 #if 0
592   struct Plugin *plugin = cls;
593 #endif
594   /* Every connection is accepted, nothing more to do here */
595   return MHD_YES;
596 }
597
598 int server_read_callback (void *cls, uint64_t pos, char *buf, int max)
599 {
600   int bytes_read = -1;
601   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "server_read_callback\n");
602   return bytes_read;
603 }
604
605 /**
606  * Process GET or PUT request received via MHD.  For
607  * GET, queue response that will send back our pending
608  * messages.  For PUT, process incoming data and send
609  * to GNUnet core.  In either case, check if a session
610  * already exists and create a new one if not.
611  */
612 static int
613 accessHandlerCallback (void *cls,
614                        struct MHD_Connection *mhd_connection,
615                        const char *url,
616                        const char *method,
617                        const char *version,
618                        const char *upload_data,
619                        size_t * upload_data_size, void **httpSessionCache)
620 {
621   struct Plugin *plugin = cls;
622   struct MHD_Response *response;
623   struct Session * cs;
624   struct HTTP_Connection_in * con;
625   const union MHD_ConnectionInfo * conn_info;
626   struct sockaddr_in  *addrin;
627   struct sockaddr_in6 *addrin6;
628   char address[INET6_ADDRSTRLEN+14];
629   struct GNUNET_PeerIdentity pi_in;
630   int res = GNUNET_NO;
631   int send_error_to_client;
632   struct IPv4HttpAddress ipv4addr;
633   struct IPv6HttpAddress ipv6addr;
634
635   GNUNET_assert(cls !=NULL);
636   send_error_to_client = GNUNET_NO;
637   if (NULL == *httpSessionCache)
638   {
639     /* check url for peer identity , if invalid send HTTP 404*/
640     res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
641     if ( GNUNET_SYSERR == res )
642     {
643       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
644       res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
645       MHD_destroy_response (response);
646       if (res == MHD_YES)
647         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, sent HTTP 1.1/404\n");
648       else
649         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, could not send error\n");
650       return res;
651     }
652   }
653   else
654   {
655     con = *httpSessionCache;
656     cs = con->session;
657   }
658
659   /* Is it a PUT or a GET request */
660   if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
661   {
662     if (NULL == *httpSessionCache)
663     {
664       /* get session for peer identity */
665       cs = session_get (plugin ,&pi_in);
666
667       conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
668       /* Incoming IPv4 connection */
669       if ( AF_INET == conn_info->client_addr->sin_family)
670       {
671         addrin = conn_info->client_addr;
672         inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
673         memcpy(&ipv4addr.ipv4_addr,&(addrin->sin_addr),sizeof(struct in_addr));
674         ipv4addr.u_port = addrin->sin_port;
675         con = session_check_inbound_address (plugin, cs, (const void *) &ipv4addr, sizeof (struct IPv4HttpAddress));
676       }
677       /* Incoming IPv6 connection */
678       if ( AF_INET6 == conn_info->client_addr->sin_family)
679       {
680         addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
681         inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
682         memcpy(&ipv6addr.ipv6_addr,&(addrin6->sin6_addr),sizeof(struct in6_addr));
683         ipv6addr.u6_port = addrin6->sin6_port;
684         con = session_check_inbound_address (plugin, cs, &ipv6addr, sizeof (struct IPv6HttpAddress));
685       }
686       /* Set closure and update current session*/
687
688       *httpSessionCache = con;
689       if (con->msgtok==NULL)
690         con->msgtok = GNUNET_SERVER_mst_create (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, &messageTokenizerCallback, con);
691
692       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"HTTP Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",
693                   method,
694                   GNUNET_i2s(&cs->identity),
695                   http_plugin_address_to_string(NULL, con->addr, con->addrlen));
696     }
697
698     if ((*upload_data_size == 0) && (con->is_put_in_progress==GNUNET_NO))
699     {
700       con->is_put_in_progress = GNUNET_YES;
701       return MHD_YES;
702     }
703
704     /* Transmission of all data complete */
705     if ((*upload_data_size == 0) && (con->is_put_in_progress == GNUNET_YES))
706     {
707         response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
708         res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
709         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sent HTTP/1.1: 200 OK as PUT Response\n",HTTP_PUT_RESPONSE, strlen (HTTP_PUT_RESPONSE), res );
710         MHD_destroy_response (response);
711         return MHD_YES;
712
713       con->is_put_in_progress = GNUNET_NO;
714       con->is_bad_request = GNUNET_NO;
715       return res;
716     }
717
718     /* Recieving data */
719     if ((*upload_data_size > 0) && (con->is_put_in_progress == GNUNET_YES))
720     {
721       res = GNUNET_SERVER_mst_receive(con->msgtok, con, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
722       (*upload_data_size) = 0;
723       return MHD_YES;
724     }
725     else
726       return MHD_NO;
727   }
728   if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
729   {
730     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Got GET Request\n");
731     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"URL: `%s'\n",url);
732
733     /* check url for peer identity , if invalid send HTTP 404*/
734     res = GNUNET_CRYPTO_hash_from_string ( &url[1], &(pi_in.hashPubKey));
735
736     if ( GNUNET_SYSERR == res )
737     {
738       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
739       res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
740       MHD_destroy_response (response);
741       if (res == MHD_YES)
742         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, sent HTTP 1.1/404\n");
743       else
744         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, could not send error\n");
745       return res;
746     }
747
748     response = MHD_create_response_from_callback(-1,32 * 1024, &server_read_callback, cs, NULL);
749     res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
750     MHD_destroy_response (response);
751
752     return res;
753
754   }
755   return MHD_NO;
756 }
757
758
759 /**
760  * Call MHD to process pending ipv4 requests and then go back
761  * and schedule the next run.
762  */
763 static void http_server_daemon_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
764 /**
765  * Call MHD to process pending ipv6 requests and then go back
766  * and schedule the next run.
767  */
768 static void http_server_daemon_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
769
770 /**
771  * Function that queries MHD's select sets and
772  * starts the task waiting for them.
773  */
774 static GNUNET_SCHEDULER_TaskIdentifier
775 http_server_daemon_prepare (void * cls, struct MHD_Daemon *daemon_handle)
776 {
777   struct Plugin *plugin = cls;
778   GNUNET_SCHEDULER_TaskIdentifier ret;
779   fd_set rs;
780   fd_set ws;
781   fd_set es;
782   struct GNUNET_NETWORK_FDSet *wrs;
783   struct GNUNET_NETWORK_FDSet *wws;
784   struct GNUNET_NETWORK_FDSet *wes;
785   int max;
786   unsigned long long timeout;
787   int haveto;
788   struct GNUNET_TIME_Relative tv;
789
790   GNUNET_assert(cls !=NULL);
791   ret = GNUNET_SCHEDULER_NO_TASK;
792   FD_ZERO(&rs);
793   FD_ZERO(&ws);
794   FD_ZERO(&es);
795   wrs = GNUNET_NETWORK_fdset_create ();
796   wes = GNUNET_NETWORK_fdset_create ();
797   wws = GNUNET_NETWORK_fdset_create ();
798   max = -1;
799   GNUNET_assert (MHD_YES ==
800                  MHD_get_fdset (daemon_handle,
801                                 &rs,
802                                 &ws,
803                                 &es,
804                                 &max));
805   haveto = MHD_get_timeout (daemon_handle, &timeout);
806   if (haveto == MHD_YES)
807     tv.value = (uint64_t) timeout;
808   else
809     tv = GNUNET_TIME_UNIT_FOREVER_REL;
810   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
811   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
812   GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
813   if (daemon_handle == plugin->http_server_daemon_v4)
814   {
815     ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
816                                        GNUNET_SCHEDULER_PRIORITY_DEFAULT,
817                                        GNUNET_SCHEDULER_NO_TASK,
818                                        tv,
819                                        wrs,
820                                        wws,
821                                        &http_server_daemon_v4_run,
822                                        plugin);
823   }
824   if (daemon_handle == plugin->http_server_daemon_v6)
825   {
826     ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
827                                        GNUNET_SCHEDULER_PRIORITY_DEFAULT,
828                                        GNUNET_SCHEDULER_NO_TASK,
829                                        tv,
830                                        wrs,
831                                        wws,
832                                        &http_server_daemon_v6_run,
833                                        plugin);
834   }
835   GNUNET_NETWORK_fdset_destroy (wrs);
836   GNUNET_NETWORK_fdset_destroy (wws);
837   GNUNET_NETWORK_fdset_destroy (wes);
838   return ret;
839 }
840
841 /**
842  * Call MHD to process pending requests and then go back
843  * and schedule the next run.
844  */
845 static void http_server_daemon_v4_run (void *cls,
846                              const struct GNUNET_SCHEDULER_TaskContext *tc)
847 {
848   struct Plugin *plugin = cls;
849
850   GNUNET_assert(cls !=NULL);
851   if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
852     plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
853
854   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
855     return;
856
857   GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v4));
858   plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
859   return;
860 }
861
862
863 /**
864  * Call MHD to process pending requests and then go back
865  * and schedule the next run.
866  */
867 static void http_server_daemon_v6_run (void *cls,
868                              const struct GNUNET_SCHEDULER_TaskContext *tc)
869 {
870   struct Plugin *plugin = cls;
871
872   GNUNET_assert(cls !=NULL);
873   if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
874     plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
875
876   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
877     return;
878
879   GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v6));
880   plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
881   return;
882 }
883
884 /**
885  * Removes a message from the linked list of messages
886  * @param con connection to remove message from
887  * @param msg message to remove
888  * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
889  */
890
891 static int remove_http_message(struct HTTP_Connection_out * con, struct HTTP_Message * msg)
892 {
893   GNUNET_CONTAINER_DLL_remove(con->pending_msgs_head,con->pending_msgs_tail,msg);
894   GNUNET_free(msg);
895   return GNUNET_OK;
896 }
897
898
899 static size_t header_function( void *ptr, size_t size, size_t nmemb, void *stream)
900 {
901   char * tmp;
902   size_t len = size * nmemb;
903
904   tmp = NULL;
905   if ((size * nmemb) < SIZE_MAX)
906     tmp = GNUNET_malloc (len+1);
907
908   if ((tmp != NULL) && (len > 0))
909   {
910     memcpy(tmp,ptr,len);
911     if (len>=2)
912     {
913       if (tmp[len-2] == 13)
914         tmp[len-2]= '\0';
915     }
916 #if DEBUG_HTTP
917     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s'\n",tmp);
918 #endif
919   }
920   if (NULL != tmp)
921     GNUNET_free (tmp);
922
923   return size * nmemb;
924 }
925
926 /**
927  * Callback method used with libcurl
928  * Method is called when libcurl needs to read data during sending
929  * @param stream pointer where to write data
930  * @param size size of an individual element
931  * @param nmemb count of elements that can be written to the buffer
932  * @param ptr source pointer, passed to the libcurl handle
933  * @return bytes written to stream
934  */
935 static size_t send_read_callback(void *stream, size_t size, size_t nmemb, void *ptr)
936 {
937   struct HTTP_Connection_out * con = ptr;
938   struct HTTP_Message * msg = con->pending_msgs_tail;
939   size_t bytes_sent;
940   size_t len;
941
942   if (con->pending_msgs_tail == NULL)
943   {
944     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: No Message to send, pausing connection\n",con);
945     con->put_send_paused = GNUNET_YES;
946     return CURL_READFUNC_PAUSE;
947   }
948
949   msg = con->pending_msgs_tail;
950   /* data to send */
951   if (msg->pos < msg->size)
952   {
953     /* data fit in buffer */
954     if ((msg->size - msg->pos) <= (size * nmemb))
955     {
956       len = (msg->size - msg->pos);
957       memcpy(stream, &msg->buf[msg->pos], len);
958       msg->pos += len;
959       bytes_sent = len;
960     }
961     else
962     {
963       len = size*nmemb;
964       memcpy(stream, &msg->buf[msg->pos], len);
965       msg->pos += len;
966       bytes_sent = len;
967     }
968   }
969   /* no data to send */
970   else
971   {
972     bytes_sent = 0;
973   }
974
975   if ( msg->pos == msg->size)
976   {
977     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Message with %u bytes sent, removing message from queue \n",con, msg->pos);
978     /* Calling transmit continuation  */
979     if (( NULL != con->pending_msgs_tail) && (NULL != con->pending_msgs_tail->transmit_cont))
980       msg->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&(con->session)->identity,GNUNET_OK);
981     remove_http_message(con, msg);
982   }
983   return bytes_sent;
984 }
985
986 /**
987 * Callback method used with libcurl
988 * Method is called when libcurl needs to write data during sending
989 * @param stream pointer where to write data
990 * @param size size of an individual element
991 * @param nmemb count of elements that can be written to the buffer
992 * @param ptr destination pointer, passed to the libcurl handle
993 * @return bytes read from stream
994 */
995 static size_t send_write_callback( void *stream, size_t size, size_t nmemb, void *ptr)
996 {
997   char * data = NULL;
998
999   if ((size * nmemb) < SIZE_MAX)
1000     data = GNUNET_malloc(size*nmemb +1);
1001   if (data != NULL)
1002   {
1003     memcpy( data, stream, size*nmemb);
1004     data[size*nmemb] = '\0';
1005     free (data);
1006   }
1007   return (size * nmemb);
1008
1009 }
1010
1011 /**
1012  * Function setting up file descriptors and scheduling task to run
1013  * @param cls closure
1014  * @param ses session to send data to
1015  * @return bytes sent to peer
1016  */
1017 static size_t send_schedule(void *cls, struct Session* ses );
1018
1019
1020
1021 /**
1022  * Function setting up curl handle and selecting message to send
1023  * @param cls plugin
1024  * @param ses session to send data to
1025  * @param con connection
1026  * @return bytes sent to peer
1027  */
1028 static ssize_t send_initiate (void *cls, struct Session* ses , struct HTTP_Connection_out *con)
1029 {
1030   struct Plugin *plugin = cls;
1031   int bytes_sent = 0;
1032   CURLMcode mret;
1033   struct HTTP_Message * msg;
1034   struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
1035
1036   GNUNET_assert(cls !=NULL);
1037
1038   if (con->get_connected == GNUNET_NO)
1039   {
1040     if (con->get_curl_handle == NULL)
1041       con->get_curl_handle = curl_easy_init();
1042
1043 #if DEBUG_CURL
1044     curl_easy_setopt(con->get_curl_handle, CURLOPT_VERBOSE, 1L);
1045 #endif
1046     curl_easy_setopt(con->get_curl_handle, CURLOPT_URL, con->url);
1047     //curl_easy_setopt(con->put_curl_handle, CURLOPT_PUT, 1L);
1048     curl_easy_setopt(con->get_curl_handle, CURLOPT_HEADERFUNCTION, &header_function);
1049     curl_easy_setopt(con->get_curl_handle, CURLOPT_WRITEHEADER, con);
1050     curl_easy_setopt(con->get_curl_handle, CURLOPT_READFUNCTION, send_read_callback);
1051     curl_easy_setopt(con->get_curl_handle, CURLOPT_READDATA, con);
1052     curl_easy_setopt(con->get_curl_handle, CURLOPT_WRITEFUNCTION, send_write_callback);
1053     curl_easy_setopt(con->get_curl_handle, CURLOPT_READDATA, con);
1054     curl_easy_setopt(con->get_curl_handle, CURLOPT_TIMEOUT, (long) timeout.value);
1055     curl_easy_setopt(con->get_curl_handle, CURLOPT_PRIVATE, con);
1056     curl_easy_setopt(con->get_curl_handle, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT_DBG);
1057     curl_easy_setopt(con->get_curl_handle, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1058
1059     mret = curl_multi_add_handle(plugin->multi_handle, con->get_curl_handle);
1060     if (mret != CURLM_OK)
1061     {
1062       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063                   _("%s failed at %s:%d: `%s'\n"),
1064                   "curl_multi_add_handle", __FILE__, __LINE__,
1065                   curl_multi_strerror (mret));
1066       return -1;
1067     }
1068
1069     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection not active\n",con);
1070   }
1071
1072   /* PUT already connected, no need to initiate connection */
1073   if ((con->put_connected == GNUNET_YES) && (con->put_curl_handle != NULL))
1074   {
1075     if (con->put_send_paused == GNUNET_NO)
1076     {
1077       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: active, enqueueing message\n",con);
1078       return bytes_sent;
1079     }
1080     if (con->put_send_paused == GNUNET_YES)
1081     {
1082       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: paused, unpausing existing connection and enqueueing message\n",con);
1083       curl_easy_pause(con->put_curl_handle,CURLPAUSE_CONT);
1084       con->put_send_paused=GNUNET_NO;
1085       return bytes_sent;
1086     }
1087   }
1088
1089
1090   /* not connected, initiate connection */
1091   if ( NULL == con->put_curl_handle)
1092     con->put_curl_handle = curl_easy_init();
1093   GNUNET_assert (con->put_curl_handle != NULL);
1094   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: not connected, initiating connection\n",con);
1095
1096   GNUNET_assert (NULL != con->pending_msgs_tail);
1097   msg = con->pending_msgs_tail;
1098
1099 #if DEBUG_CURL
1100   curl_easy_setopt(con->put_curl_handle, CURLOPT_VERBOSE, 1L);
1101 #endif
1102   curl_easy_setopt(con->put_curl_handle, CURLOPT_URL, con->url);
1103   curl_easy_setopt(con->put_curl_handle, CURLOPT_PUT, 1L);
1104   curl_easy_setopt(con->put_curl_handle, CURLOPT_HEADERFUNCTION, &header_function);
1105   curl_easy_setopt(con->put_curl_handle, CURLOPT_WRITEHEADER, con);
1106   curl_easy_setopt(con->put_curl_handle, CURLOPT_READFUNCTION, send_read_callback);
1107   curl_easy_setopt(con->put_curl_handle, CURLOPT_READDATA, con);
1108   curl_easy_setopt(con->put_curl_handle, CURLOPT_WRITEFUNCTION, send_write_callback);
1109   curl_easy_setopt(con->put_curl_handle, CURLOPT_READDATA, con);
1110   curl_easy_setopt(con->put_curl_handle, CURLOPT_TIMEOUT, (long) timeout.value);
1111   curl_easy_setopt(con->put_curl_handle, CURLOPT_PRIVATE, con);
1112   curl_easy_setopt(con->put_curl_handle, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT_DBG);
1113   curl_easy_setopt(con->put_curl_handle, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1114
1115   mret = curl_multi_add_handle(plugin->multi_handle, con->put_curl_handle);
1116   if (mret != CURLM_OK)
1117   {
1118     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1119                 _("%s failed at %s:%d: `%s'\n"),
1120                 "curl_multi_add_handle", __FILE__, __LINE__,
1121                 curl_multi_strerror (mret));
1122     return -1;
1123   }
1124   con->put_connected = GNUNET_YES;
1125   bytes_sent = send_schedule (plugin, ses);
1126   return bytes_sent;
1127 }
1128
1129 static void send_execute (void *cls,
1130              const struct GNUNET_SCHEDULER_TaskContext *tc)
1131 {
1132   struct Plugin *plugin = cls;
1133   static unsigned int handles_last_run;
1134   int running;
1135   struct CURLMsg *msg;
1136   CURLMcode mret;
1137   struct HTTP_Connection_out * con = NULL;
1138   struct Session * cs = NULL;
1139   long http_result;
1140
1141   GNUNET_assert(cls !=NULL);
1142   plugin->http_server_task_send = GNUNET_SCHEDULER_NO_TASK;
1143   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1144     return;
1145
1146   do
1147     {
1148       running = 0;
1149       mret = curl_multi_perform (plugin->multi_handle, &running);
1150       if (running < handles_last_run)
1151         {
1152           do
1153             {
1154
1155               msg = curl_multi_info_read (plugin->multi_handle, &running);
1156               if (msg == NULL)
1157                 break;
1158               /* get session for affected curl handle */
1159               GNUNET_assert ( msg->easy_handle != NULL );
1160               curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char *) &con);
1161               GNUNET_assert ( con != NULL );
1162               cs = con->session;
1163               GNUNET_assert ( cs != NULL );
1164               switch (msg->msg)
1165                 {
1166
1167                 case CURLMSG_DONE:
1168                   if ( (msg->data.result != CURLE_OK) &&
1169                        (msg->data.result != CURLE_GOT_NOTHING) )
1170                   {
1171
1172
1173                     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1174                                _("Connection %X to peer `%s' (`%s') failed: `%s' `%s'\n"),
1175                                con,
1176                                GNUNET_i2s(&cs->identity),
1177                                http_plugin_address_to_string(NULL, con->addr, con->addrlen),
1178                                "curl_multi_perform",
1179                                curl_easy_strerror (msg->data.result));
1180                     /* sending msg failed*/
1181                     con->put_connected = GNUNET_NO;
1182                     curl_easy_cleanup(con->put_curl_handle);
1183                     con->put_curl_handle=NULL;
1184                     if (( NULL != con->pending_msgs_tail) && ( NULL != con->pending_msgs_tail->transmit_cont))
1185                       con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&con->session->identity,GNUNET_SYSERR);
1186
1187                   }
1188                   else
1189                   {
1190                     GNUNET_assert (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_result));
1191                     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1192                                 "Send to peer `%s' completed with code %u\n", GNUNET_i2s(&cs->identity), http_result );
1193
1194                     curl_easy_cleanup(con->put_curl_handle);
1195                     con->put_connected = GNUNET_NO;
1196                     con->put_curl_handle=NULL;
1197
1198                     /* Calling transmit continuation  */
1199                     if (( NULL != con->pending_msgs_tail) && (NULL != con->pending_msgs_tail->transmit_cont))
1200                     {
1201                       /* HTTP 1xx : Last message before here was informational */
1202                       if ((http_result >=100) && (http_result < 200))
1203                         con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&cs->identity,GNUNET_OK);
1204                       /* HTTP 2xx: successful operations */
1205                       if ((http_result >=200) && (http_result < 300))
1206                         con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&cs->identity,GNUNET_OK);
1207                       /* HTTP 3xx..5xx: error */
1208                       if ((http_result >=300) && (http_result < 600))
1209                         con->pending_msgs_tail->transmit_cont (con->pending_msgs_tail->transmit_cont_cls,&cs->identity,GNUNET_SYSERR);
1210                     }
1211                   }
1212                   if (con->pending_msgs_tail != NULL)
1213                   {
1214                     if (con->pending_msgs_tail->pos>0)
1215                       remove_http_message(con, con->pending_msgs_tail);
1216                     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message could not be removed from session `%s'\n", GNUNET_i2s(&cs->identity));
1217                   }
1218                   return;
1219                 default:
1220                   break;
1221                 }
1222
1223             }
1224           while ( (running > 0) );
1225         }
1226       handles_last_run = running;
1227     }
1228   while (mret == CURLM_CALL_MULTI_PERFORM);
1229   send_schedule(plugin, cls);
1230 }
1231
1232
1233 /**
1234  * Function setting up file descriptors and scheduling task to run
1235  * @param ses session to send data to
1236  * @return bytes sent to peer
1237  */
1238 static size_t send_schedule(void *cls, struct Session* ses )
1239 {
1240   struct Plugin *plugin = cls;
1241   fd_set rs;
1242   fd_set ws;
1243   fd_set es;
1244   int max;
1245   struct GNUNET_NETWORK_FDSet *grs;
1246   struct GNUNET_NETWORK_FDSet *gws;
1247   long to;
1248   CURLMcode mret;
1249
1250   GNUNET_assert(cls !=NULL);
1251   max = -1;
1252   FD_ZERO (&rs);
1253   FD_ZERO (&ws);
1254   FD_ZERO (&es);
1255   mret = curl_multi_fdset (plugin->multi_handle, &rs, &ws, &es, &max);
1256   if (mret != CURLM_OK)
1257     {
1258       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1259                   _("%s failed at %s:%d: `%s'\n"),
1260                   "curl_multi_fdset", __FILE__, __LINE__,
1261                   curl_multi_strerror (mret));
1262       return -1;
1263     }
1264   mret = curl_multi_timeout (plugin->multi_handle, &to);
1265   if (mret != CURLM_OK)
1266     {
1267       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1268                   _("%s failed at %s:%d: `%s'\n"),
1269                   "curl_multi_timeout", __FILE__, __LINE__,
1270                   curl_multi_strerror (mret));
1271       return -1;
1272     }
1273
1274   grs = GNUNET_NETWORK_fdset_create ();
1275   gws = GNUNET_NETWORK_fdset_create ();
1276   GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
1277   GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
1278   plugin->http_server_task_send = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1279                                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1280                                    GNUNET_SCHEDULER_NO_TASK,
1281                                    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
1282                                    grs,
1283                                    gws,
1284                                    &send_execute,
1285                                    plugin);
1286   GNUNET_NETWORK_fdset_destroy (gws);
1287   GNUNET_NETWORK_fdset_destroy (grs);
1288
1289   /* FIXME: return bytes REALLY sent */
1290   return 0;
1291 }
1292
1293
1294 /**
1295  * Function that can be used by the transport service to transmit
1296  * a message using the plugin.   Note that in the case of a
1297  * peer disconnecting, the continuation MUST be called
1298  * prior to the disconnect notification itself.  This function
1299  * will be called with this peer's HELLO message to initiate
1300  * a fresh connection to another peer.
1301  *
1302  * @param cls closure
1303  * @param target who should receive this message
1304  * @param msgbuf the message to transmit
1305  * @param msgbuf_size number of bytes in 'msgbuf'
1306  * @param priority how important is the message (most plugins will
1307  *                 ignore message priority and just FIFO)
1308  * @param timeout how long to wait at most for the transmission (does not
1309  *                require plugins to discard the message after the timeout,
1310  *                just advisory for the desired delay; most plugins will ignore
1311  *                this as well)
1312  * @param session which session must be used (or NULL for "any")
1313  * @param addr the address to use (can be NULL if the plugin
1314  *                is "on its own" (i.e. re-use existing TCP connection))
1315  * @param addrlen length of the address in bytes
1316  * @param force_address GNUNET_YES if the plugin MUST use the given address,
1317  *                GNUNET_NO means the plugin may use any other address and
1318  *                GNUNET_SYSERR means that only reliable existing
1319  *                bi-directional connections should be used (regardless
1320  *                of address)
1321  * @param cont continuation to call once the message has
1322  *        been transmitted (or if the transport is ready
1323  *        for the next transmission call; or if the
1324  *        peer disconnected...); can be NULL
1325  * @param cont_cls closure for cont
1326  * @return number of bytes used (on the physical network, with overheads);
1327  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
1328  *         and does NOT mean that the message was not transmitted (DV)
1329  */
1330 static ssize_t
1331 http_plugin_send (void *cls,
1332                   const struct GNUNET_PeerIdentity *target,
1333                   const char *msgbuf,
1334                   size_t msgbuf_size,
1335                   unsigned int priority,
1336                   struct GNUNET_TIME_Relative to,
1337                   struct Session *session,
1338                   const void *addr,
1339                   size_t addrlen,
1340                   int force_address,
1341                   GNUNET_TRANSPORT_TransmitContinuation cont,
1342                   void *cont_cls)
1343 {
1344   struct Plugin *plugin = cls;
1345   struct Session *cs;
1346   struct HTTP_Message *msg;
1347   struct HTTP_Connection_out *con;
1348   //unsigned int ret;
1349
1350   GNUNET_assert(cls !=NULL);
1351   GNUNET_assert ((addr!=NULL) && (addrlen != 0));
1352
1353   /* get session from hashmap */
1354   cs = session_get(plugin, target);
1355   con = session_check_outbound_address(plugin, cs, addr, addrlen);
1356
1357   char * force = GNUNET_malloc(30);
1358
1359   if (force_address == GNUNET_YES)
1360     strcpy(force,"forced addr.");
1361   if (force_address == GNUNET_NO)
1362     strcpy(force,"any addr.");
1363   if (force_address == GNUNET_SYSERR)
1364     strcpy(force,"reliable bi-direc. address addr.");
1365   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to `%s' %s (%s), session: %X\n",
1366                                       msgbuf_size,
1367                                       GNUNET_i2s(&cs->identity),
1368                                       force,
1369                                       http_plugin_address_to_string(NULL, addr, addrlen),
1370                                       session);
1371
1372   //GNUNET_free(force);
1373   /* create msg */
1374   msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
1375   msg->next = NULL;
1376   msg->size = msgbuf_size;
1377   msg->pos = 0;
1378   msg->buf = (char *) &msg[1];
1379   msg->transmit_cont = cont;
1380   msg->transmit_cont_cls = cont_cls;
1381   memcpy (msg->buf,msgbuf, msgbuf_size);
1382
1383   /* must use this address */
1384   if (force_address == GNUNET_YES)
1385   {
1386     /* enqueue in connection message queue */
1387     GNUNET_CONTAINER_DLL_insert(con->pending_msgs_head,con->pending_msgs_tail,msg);
1388   }
1389   /* can use existing connection to send */
1390   else
1391   {
1392     /* enqueue in connection message queue */
1393     GNUNET_CONTAINER_DLL_insert(con->pending_msgs_head,con->pending_msgs_tail,msg);
1394   }
1395   return send_initiate (plugin, cs, con);
1396 }
1397
1398
1399
1400 /**
1401  * Function that can be used to force the plugin to disconnect
1402  * from the given peer and cancel all previous transmissions
1403  * (and their continuationc).
1404  *
1405  * @param cls closure
1406  * @param target peer from which to disconnect
1407  */
1408 static void
1409 http_plugin_disconnect (void *cls,
1410                             const struct GNUNET_PeerIdentity *target)
1411 {
1412   struct Plugin *plugin = cls;
1413   struct HTTP_Connection_out *con;
1414   struct Session *cs;
1415
1416   /* get session from hashmap */
1417   cs = session_get(plugin, target);
1418   con = cs->outbound_connections_head;
1419
1420   while (con!=NULL)
1421   {
1422     if (con->put_curl_handle!=NULL)
1423       curl_easy_cleanup(con->put_curl_handle);
1424     con->put_curl_handle=NULL;
1425     con->put_connected = GNUNET_NO;
1426     while (con->pending_msgs_head!=NULL)
1427     {
1428       remove_http_message(con, con->pending_msgs_head);
1429     }
1430     con=con->next;
1431   }
1432 }
1433
1434
1435 /**
1436  * Convert the transports address to a nice, human-readable
1437  * format.
1438  *
1439  * @param cls closure
1440  * @param type name of the transport that generated the address
1441  * @param addr one of the addresses of the host, NULL for the last address
1442  *        the specific address format depends on the transport
1443  * @param addrlen length of the address
1444  * @param numeric should (IP) addresses be displayed in numeric form?
1445  * @param timeout after how long should we give up?
1446  * @param asc function to call on each string
1447  * @param asc_cls closure for asc
1448  */
1449 static void
1450 http_plugin_address_pretty_printer (void *cls,
1451                                         const char *type,
1452                                         const void *addr,
1453                                         size_t addrlen,
1454                                         int numeric,
1455                                         struct GNUNET_TIME_Relative timeout,
1456                                         GNUNET_TRANSPORT_AddressStringCallback
1457                                         asc, void *asc_cls)
1458 {
1459   const struct IPv4HttpAddress *t4;
1460   const struct IPv6HttpAddress *t6;
1461   struct sockaddr_in a4;
1462   struct sockaddr_in6 a6;
1463   char * address;
1464   char * ret;
1465   unsigned int port;
1466   unsigned int res;
1467
1468   GNUNET_assert(cls !=NULL);
1469   if (addrlen == sizeof (struct IPv6HttpAddress))
1470   {
1471     address = GNUNET_malloc (INET6_ADDRSTRLEN);
1472     t6 = addr;
1473     a6.sin6_addr = t6->ipv6_addr;
1474     inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
1475     port = ntohs(t6->u6_port);
1476   }
1477   else if (addrlen == sizeof (struct IPv4HttpAddress))
1478   {
1479     address = GNUNET_malloc (INET_ADDRSTRLEN);
1480     t4 = addr;
1481     a4.sin_addr.s_addr =  t4->ipv4_addr;
1482     inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
1483     port = ntohs(t4->u_port);
1484   }
1485   else
1486   {
1487     /* invalid address */
1488     GNUNET_break_op (0);
1489     asc (asc_cls, NULL);
1490     return;
1491   }
1492   res = GNUNET_asprintf(&ret,"http://%s:%u/",address,port);
1493   GNUNET_free (address);
1494   GNUNET_assert(res != 0);
1495
1496   asc (asc_cls, ret);
1497 }
1498
1499
1500
1501 /**
1502  * Another peer has suggested an address for this
1503  * peer and transport plugin.  Check that this could be a valid
1504  * address.  If so, consider adding it to the list
1505  * of addresses.
1506  *
1507  * @param cls closure
1508  * @param addr pointer to the address
1509  * @param addrlen length of addr
1510  * @return GNUNET_OK if this is a plausible address for this peer
1511  *         and transport
1512  */
1513 static int
1514 http_plugin_address_suggested (void *cls,
1515                                const void *addr, size_t addrlen)
1516 {
1517   struct Plugin *plugin = cls;
1518   struct IPv4HttpAddress *v4;
1519   struct IPv6HttpAddress *v6;
1520   unsigned int port;
1521
1522   GNUNET_assert(cls !=NULL);
1523   if ((addrlen != sizeof (struct IPv4HttpAddress)) &&
1524       (addrlen != sizeof (struct IPv6HttpAddress)))
1525     {
1526       return GNUNET_SYSERR;
1527     }
1528   if (addrlen == sizeof (struct IPv4HttpAddress))
1529     {
1530       v4 = (struct IPv4HttpAddress *) addr;
1531       if (INADDR_LOOPBACK == ntohl(v4->ipv4_addr))
1532       {
1533         return GNUNET_SYSERR;
1534       }
1535       port = ntohs (v4->u_port);
1536       if (port != plugin->port_inbound)
1537       {
1538         return GNUNET_SYSERR;
1539       }
1540     }
1541   else
1542     {
1543       v6 = (struct IPv6HttpAddress *) addr;
1544       if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
1545         {
1546           return GNUNET_SYSERR;
1547         }
1548       port = ntohs (v6->u6_port);
1549       if (port != plugin->port_inbound)
1550       {
1551         return GNUNET_SYSERR;
1552       }
1553     }
1554   return GNUNET_OK;
1555 }
1556
1557
1558 /**
1559  * Function called for a quick conversion of the binary address to
1560  * a numeric address.  Note that the caller must not free the
1561  * address and that the next call to this function is allowed
1562  * to override the address again.
1563  *
1564  * @param cls closure
1565  * @param addr binary address
1566  * @param addrlen length of the address
1567  * @return string representing the same address
1568  */
1569 static const char*
1570 http_plugin_address_to_string (void *cls,
1571                                    const void *addr,
1572                                    size_t addrlen)
1573 {
1574   const struct IPv4HttpAddress *t4;
1575   const struct IPv6HttpAddress *t6;
1576   struct sockaddr_in a4;
1577   struct sockaddr_in6 a6;
1578   char * address;
1579   char * ret;
1580   uint16_t port;
1581   unsigned int res;
1582
1583   if (addrlen == sizeof (struct IPv6HttpAddress))
1584     {
1585       address = GNUNET_malloc (INET6_ADDRSTRLEN);
1586       t6 = addr;
1587       a6.sin6_addr = t6->ipv6_addr;
1588       inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
1589       port = ntohs(t6->u6_port);
1590     }
1591   else if (addrlen == sizeof (struct IPv4HttpAddress))
1592     {
1593       address = GNUNET_malloc (INET_ADDRSTRLEN);
1594       t4 = addr;
1595       a4.sin_addr.s_addr =  t4->ipv4_addr;
1596       inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
1597       port = ntohs(t4->u_port);
1598     }
1599   else
1600     {
1601       /* invalid address */
1602       return NULL;
1603     }
1604   res = GNUNET_asprintf(&ret,"%s:%u",address,port);
1605   GNUNET_free (address);
1606   GNUNET_assert(res != 0);
1607   return ret;
1608 }
1609
1610 /**
1611  * Add the IP of our network interface to the list of
1612  * our external IP addresses.
1613  *
1614  * @param cls the 'struct Plugin*'
1615  * @param name name of the interface
1616  * @param isDefault do we think this may be our default interface
1617  * @param addr address of the interface
1618  * @param addrlen number of bytes in addr
1619  * @return GNUNET_OK to continue iterating
1620  */
1621 static int
1622 process_interfaces (void *cls,
1623                     const char *name,
1624                     int isDefault,
1625                     const struct sockaddr *addr, socklen_t addrlen)
1626 {
1627   struct Plugin *plugin = cls;
1628   struct IPv4HttpAddress * t4;
1629   struct IPv6HttpAddress * t6;
1630   int af;
1631
1632   GNUNET_assert(cls !=NULL);
1633   af = addr->sa_family;
1634   if (af == AF_INET)
1635     {
1636       t4 = GNUNET_malloc(sizeof(struct IPv4HttpAddress));
1637       if (INADDR_LOOPBACK == ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr))
1638       {
1639         /* skip loopback addresses */
1640         return GNUNET_OK;
1641       }
1642       t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1643       t4->u_port = htons (plugin->port_inbound);
1644       plugin->env->notify_address(plugin->env->cls,"http",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
1645
1646     }
1647   else if (af == AF_INET6)
1648     {
1649       t6 = GNUNET_malloc(sizeof(struct IPv6HttpAddress));
1650       if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
1651         {
1652           /* skip link local addresses */
1653           return GNUNET_OK;
1654         }
1655       if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))
1656         {
1657           /* skip loopback addresses */
1658           return GNUNET_OK;
1659         }
1660       memcpy (&t6->ipv6_addr,
1661               &((struct sockaddr_in6 *) addr)->sin6_addr,
1662               sizeof (struct in6_addr));
1663       t6->u6_port = htons (plugin->port_inbound);
1664       plugin->env->notify_address(plugin->env->cls,"http",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
1665     }
1666   return GNUNET_OK;
1667 }
1668 int hashMapFreeIterator (void *cls, const GNUNET_HashCode *key, void *value)
1669 {
1670   struct Session * cs = value;
1671   struct HTTP_Connection_out * con = cs->outbound_connections_head;
1672   struct HTTP_Connection_out * tmp_con = cs->outbound_connections_head;
1673   struct HTTP_Message * msg = NULL;
1674   struct HTTP_Message * tmp_msg = NULL;
1675
1676   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing session for peer `%s'\n",GNUNET_i2s(&cs->identity));
1677
1678   /* freeing connections */
1679   while (con!=NULL)
1680   {
1681     GNUNET_free(con->url);
1682     if (con->put_curl_handle!=NULL)
1683       curl_easy_cleanup(con->put_curl_handle);
1684     con->put_curl_handle = NULL;
1685     msg = con->pending_msgs_head;
1686     while (msg!=NULL)
1687     {
1688       tmp_msg=msg->next;
1689       GNUNET_free(msg);
1690       msg = tmp_msg;
1691     }
1692     tmp_con=con->next;
1693     GNUNET_free(con);
1694     con=tmp_con;
1695   }
1696   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"All sessions freed \n");
1697
1698   GNUNET_free (cs);
1699   return GNUNET_YES;
1700 }
1701
1702 /**
1703  * Exit point from the plugin.
1704  */
1705 void *
1706 libgnunet_plugin_transport_http_done (void *cls)
1707 {
1708   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1709   struct Plugin *plugin = api->cls;
1710   CURLMcode mret;
1711
1712   GNUNET_assert(cls !=NULL);
1713
1714
1715   if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1716   {
1717     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
1718     plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
1719   }
1720
1721   if ( plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1722   {
1723     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
1724     plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1725   }
1726
1727   if ( plugin->http_server_task_send != GNUNET_SCHEDULER_NO_TASK)
1728   {
1729     GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_send);
1730     plugin->http_server_task_send = GNUNET_SCHEDULER_NO_TASK;
1731   }
1732
1733   if (plugin->http_server_daemon_v4 != NULL)
1734   {
1735     MHD_stop_daemon (plugin->http_server_daemon_v4);
1736     plugin->http_server_daemon_v4 = NULL;
1737   }
1738   if (plugin->http_server_daemon_v6 != NULL)
1739   {
1740     MHD_stop_daemon (plugin->http_server_daemon_v6);
1741     plugin->http_server_daemon_v6 = NULL;
1742   }
1743
1744   /* free all sessions */
1745   GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions,
1746                                          &hashMapFreeIterator,
1747                                          NULL);
1748
1749   GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions);
1750
1751   mret = curl_multi_cleanup(plugin->multi_handle);
1752   if ( CURLM_OK != mret)
1753     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed");
1754
1755   GNUNET_free (plugin);
1756   GNUNET_free (api);
1757   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unload http plugin complete...\n");
1758   return NULL;
1759 }
1760
1761
1762 /**
1763  * Entry point for the plugin.
1764  */
1765 void *
1766 libgnunet_plugin_transport_http_init (void *cls)
1767 {
1768   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1769   struct Plugin *plugin;
1770   struct GNUNET_TRANSPORT_PluginFunctions *api;
1771   struct GNUNET_TIME_Relative gn_timeout;
1772   long long unsigned int port;
1773
1774   GNUNET_assert(cls !=NULL);
1775   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting http plugin...\n");
1776
1777   plugin = GNUNET_malloc (sizeof (struct Plugin));
1778   plugin->env = env;
1779   plugin->sessions = NULL;
1780
1781   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1782   api->cls = plugin;
1783   api->send = &http_plugin_send;
1784   api->disconnect = &http_plugin_disconnect;
1785   api->address_pretty_printer = &http_plugin_address_pretty_printer;
1786   api->check_address = &http_plugin_address_suggested;
1787   api->address_to_string = &http_plugin_address_to_string;
1788
1789   /* Hashing our identity to use it in URLs */
1790   GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &plugin->my_ascii_hash_ident);
1791
1792   /* Reading port number from config file */
1793   if ((GNUNET_OK !=
1794        GNUNET_CONFIGURATION_get_value_number (env->cfg,
1795                                               "transport-http",
1796                                               "PORT",
1797                                               &port)) ||
1798       (port > 65535) )
1799     {
1800       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1801                        "http",
1802                        _
1803                        ("Require valid port number for transport plugin `%s' in configuration!\n"),
1804                        "transport-http");
1805       libgnunet_plugin_transport_http_done (api);
1806       return NULL;
1807     }
1808   GNUNET_assert ((port > 0) && (port <= 65535));
1809   plugin->port_inbound = port;
1810   gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
1811   if ((plugin->http_server_daemon_v4 == NULL) && (plugin->http_server_daemon_v6 == NULL) && (port != 0))
1812     {
1813     plugin->http_server_daemon_v6 = MHD_start_daemon (MHD_USE_IPv6,
1814                                        port,
1815                                        &acceptPolicyCallback,
1816                                        plugin , &accessHandlerCallback, plugin,
1817                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
1818                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1819                                        MHD_OPTION_CONNECTION_TIMEOUT, (gn_timeout.value / 1000),
1820                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
1821                                        MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
1822                                        MHD_OPTION_END);
1823     plugin->http_server_daemon_v4 = MHD_start_daemon (MHD_NO_FLAG,
1824                                        port,
1825                                        &acceptPolicyCallback,
1826                                        plugin , &accessHandlerCallback, plugin,
1827                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
1828                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1829                                        MHD_OPTION_CONNECTION_TIMEOUT, (gn_timeout.value / 1000),
1830                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
1831                                        MHD_OPTION_NOTIFY_COMPLETED, &requestCompletedCallback, NULL,
1832                                        MHD_OPTION_END);
1833     }
1834   if (plugin->http_server_daemon_v4 != NULL)
1835     plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
1836   if (plugin->http_server_daemon_v6 != NULL)
1837     plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
1838
1839   if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1840     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 on port %u\n",port);
1841   else if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1842     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 on port %u\n",port);
1843   else
1844   {
1845     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No MHD was started, transport plugin not functional!\n");
1846     libgnunet_plugin_transport_http_done (api);
1847     return NULL;
1848   }
1849
1850   /* Initializing cURL */
1851   curl_global_init(CURL_GLOBAL_ALL);
1852   plugin->multi_handle = curl_multi_init();
1853
1854   if ( NULL == plugin->multi_handle )
1855   {
1856     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1857                      "http",
1858                      _("Could not initialize curl multi handle, failed to start http plugin!\n"),
1859                      "transport-http");
1860     libgnunet_plugin_transport_http_done (api);
1861     return NULL;
1862   }
1863
1864   plugin->sessions = GNUNET_CONTAINER_multihashmap_create (10);
1865   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
1866
1867   return api;
1868 }
1869
1870 /* end of plugin_transport_http.c */