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