e3cd735599e59fa7969dd2611653c88954372d1d
[oweals/gnunet.git] / src / transport / plugin_transport_http_server.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_server.c
23  * @brief HTTP/S server transport plugin
24  * @author Matthias Wachs
25  */
26
27 #include "platform.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_connection_lib.h"
30 #include "gnunet_server_lib.h"
31 #include "gnunet_service_lib.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet_transport_plugin.h"
35
36 #include "gnunet_container_lib.h"
37 #include "gnunet_nat_lib.h"
38 #include "plugin_transport_http_common.h"
39 #include "microhttpd.h"
40
41 #if BUILD_HTTPS
42 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_server_init
43 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_server_done
44 #else
45 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_server_init
46 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_server_done
47 #endif
48
49 #define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
50
51 #define TESTING GNUNET_NO
52
53 #if TESTING
54 #define TIMEOUT_LOG GNUNET_ERROR_TYPE_ERROR
55 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
56 #else
57 #define TIMEOUT_LOG GNUNET_ERROR_TYPE_DEBUG
58 #define TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
59 #endif
60
61 #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>"
62 #define _RECEIVE 0
63 #define _SEND 1
64
65 /**
66  * Encapsulation of all of the state of the plugin.
67  */
68 struct Plugin;
69
70 /**
71  * Session handle for connections.
72  */
73 struct Session
74 {
75   /**
76    * Stored in a linked list.
77    */
78   struct Session *next;
79
80   /**
81    * Stored in a linked list.
82    */
83   struct Session *prev;
84
85   /**
86    * To whom are we talking to (set to our identity
87    * if we are still waiting for the welcome message)
88    */
89   struct GNUNET_PeerIdentity target;
90
91   /**
92    * Pointer to the global plugin struct.
93    */
94   struct HTTP_Server_Plugin *plugin;
95
96   /**
97    * next pointer for double linked list
98    */
99   struct HTTP_Message *msg_head;
100
101   /**
102    * previous pointer for double linked list
103    */
104   struct HTTP_Message *msg_tail;
105
106   /**
107    * Message stream tokenizer for incoming data
108    */
109   struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
110
111   /**
112    * Client send handle
113    */
114   struct ServerConnection *server_recv;
115
116   /**
117    * Client send handle
118    */
119   struct ServerConnection *server_send;
120
121   /**
122    * Address
123    */
124   void *addr;
125
126   size_t addrlen;
127
128   /**
129    * Inbound or outbound connection
130    * Outbound: GNUNET_NO (client is used to send and receive)
131    * Inbound : GNUNET_YES (server is used to send and receive)
132    */
133   int inbound;
134
135   /**
136    * Unique HTTP/S connection tag for this connection
137    */
138   uint32_t tag;
139
140   /**
141    * ATS network type in NBO
142    */
143   uint32_t ats_address_network_type;
144
145   /**
146    * Absolute time when to receive data again
147    * Used for receive throttling
148    */
149   struct GNUNET_TIME_Absolute next_receive;
150
151   /**
152    * Session timeout task
153    */
154   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
155 };
156
157 struct ServerConnection
158 {
159   /* _RECV or _SEND */
160   int direction;
161
162   /* Should this connection get disconnected? GNUNET_YES/NO  */
163   int disconnect;
164
165   /* The session this server connection belongs to */
166   struct Session *session;
167
168   /* The MHD connection */
169   struct MHD_Connection *mhd_conn;
170
171   /* The MHD daemon */
172   struct MHD_Daemon *mhd_daemon;
173 };
174
175 /**
176  * Encapsulation of all of the state of the plugin.
177  */
178 struct HTTP_Server_Plugin
179 {
180   /**
181    * Our environment.
182    */
183   struct GNUNET_TRANSPORT_PluginEnvironment *env;
184
185   /**
186    * Linked list head of open sessions.
187    */
188
189   struct Session *head;
190
191   /**
192    * Linked list tail of open sessions.
193    */
194   struct Session *tail;
195
196   /**
197    * Plugin name
198    */
199   char *name;
200
201   /**
202    * Protocol
203    */
204   char *protocol;
205
206   /**
207    * External address
208    */
209   char *external_hostname;
210
211   /**
212    * Maximum number of sockets the plugin can use
213    * Each http inbound /outbound connections are two connections
214    */
215   unsigned int max_connections;
216
217   /**
218    * Current number of sockets the plugin can use
219    * Each http inbound /outbound connections are two connections
220    */
221   unsigned int cur_connections;
222
223   /**
224    * External hostname the plugin can be connected to, can be different to
225    * the host's FQDN, used e.g. for reverse proxying
226    */
227   char *ext_addr;
228
229   /**
230    * External address length
231    */
232   size_t ext_addr_len;
233
234   /**
235    * use IPv6
236    */
237   uint16_t use_ipv6;
238
239   /**
240    * use IPv4
241    */
242   uint16_t use_ipv4;
243
244   /**
245    * Port used
246    */
247   uint16_t port;
248
249   /**
250    * Task calling transport service about external address
251    */
252   GNUNET_SCHEDULER_TaskIdentifier notify_ext_task;
253
254   /**
255    * NAT handle & address management
256    */
257   struct GNUNET_NAT_Handle *nat;
258
259   /**
260    * Server semi connections
261    * A full session consists of 2 semi-connections: send and receive
262    * If not both directions are established the server keeps this sessions here
263    */
264   struct Session *server_semi_head;
265
266   struct Session *server_semi_tail;
267
268   /**
269    * List of own addresses
270    */
271
272   /**
273    * IPv4 addresses DLL head
274    */
275   struct HttpAddressWrapper *addr_head;
276
277   /**
278    * IPv4 addresses DLL tail
279    */
280   struct HttpAddressWrapper *addr_tail;
281
282   /**
283    * IPv4 server socket to bind to
284    */
285   struct sockaddr_in *server_addr_v4;
286
287   /**
288    * IPv6 server socket to bind to
289    */
290   struct sockaddr_in6 *server_addr_v6;
291
292   /**
293    * MHD IPv4 task
294    */
295   GNUNET_SCHEDULER_TaskIdentifier server_v4_task;
296
297   /**
298    * MHD IPv6 task
299    */
300   GNUNET_SCHEDULER_TaskIdentifier server_v6_task;
301
302   /**
303    * The IPv4 server is scheduled to run asap
304    */
305   int server_v4_immediately;
306
307   /**
308    * The IPv6 server is scheduled to run asap
309    */
310   int server_v6_immediately;
311
312   /**
313    * MHD IPv4 daemon
314    */
315   struct MHD_Daemon *server_v4;
316
317   /**
318    * MHD IPv4 daemon
319    */
320   struct MHD_Daemon *server_v6;
321
322 #if BUILD_HTTPS
323   /**
324    * Crypto related
325    *
326    * Example:
327    *
328    * Use RC4-128 instead of AES:
329    * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL
330    *
331    */
332   char *crypto_init;
333
334   /**
335    * TLS key
336    */
337   char *key;
338
339   /**
340    * TLS certificate
341    */
342   char *cert;
343 #endif
344
345 };
346
347 /**
348  * Wrapper to manage addresses
349  */
350 struct HttpAddressWrapper
351 {
352   /**
353    * Linked list next
354    */
355   struct HttpAddressWrapper *next;
356
357   /**
358    * Linked list previous
359    */
360   struct HttpAddressWrapper *prev;
361
362   void *addr;
363
364   size_t addrlen;
365 };
366
367 /**
368  *  Message to send using http
369  */
370 struct HTTP_Message
371 {
372   /**
373    * next pointer for double linked list
374    */
375   struct HTTP_Message *next;
376
377   /**
378    * previous pointer for double linked list
379    */
380   struct HTTP_Message *prev;
381
382   /**
383    * buffer containing data to send
384    */
385   char *buf;
386
387   /**
388    * amount of data already sent
389    */
390   size_t pos;
391
392   /**
393    * buffer length
394    */
395   size_t size;
396
397   /**
398    * Continuation function to call once the transmission buffer
399    * has again space available.  NULL if there is no
400    * continuation to call.
401    */
402   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
403
404   /**
405    * Closure for transmit_cont.
406    */
407   void *transmit_cont_cls;
408 };
409
410
411 static struct HTTP_Server_Plugin * p;
412
413 /**
414  * Start session timeout
415  */
416 static void
417 server_start_session_timeout (struct Session *s);
418
419 /**
420  * Increment session timeout due to activity
421  */
422 static void
423 server_reschedule_session_timeout (struct Session *s);
424
425 /**
426  * Cancel timeout
427  */
428 static void
429 server_stop_session_timeout (struct Session *s);
430
431 /**
432  * Function that can be used by the transport service to transmit
433  * a message using the plugin.   Note that in the case of a
434  * peer disconnecting, the continuation MUST be called
435  * prior to the disconnect notification itself.  This function
436  * will be called with this peer's HELLO message to initiate
437  * a fresh connection to another peer.
438  *
439  * @param cls closure
440  * @param session which session must be used
441  * @param msgbuf the message to transmit
442  * @param msgbuf_size number of bytes in 'msgbuf'
443  * @param priority how important is the message (most plugins will
444  *                 ignore message priority and just FIFO)
445  * @param to how long to wait at most for the transmission (does not
446  *                require plugins to discard the message after the timeout,
447  *                just advisory for the desired delay; most plugins will ignore
448  *                this as well)
449  * @param cont continuation to call once the message has
450  *        been transmitted (or if the transport is ready
451  *        for the next transmission call; or if the
452  *        peer disconnected...); can be NULL
453  * @param cont_cls closure for cont
454  * @return number of bytes used (on the physical network, with overheads);
455  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
456  *         and does NOT mean that the message was not transmitted (DV)
457  */
458 static ssize_t
459 http_server_plugin_send (void *cls,
460                   struct Session *session,
461                   const char *msgbuf, size_t msgbuf_size,
462                   unsigned int priority,
463                   struct GNUNET_TIME_Relative to,
464                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
465 {
466   struct HTTP_Server_Plugin *plugin = cls;
467   int bytes_sent = 0;
468
469   GNUNET_assert (plugin != NULL);
470   GNUNET_assert (session != NULL);
471
472   GNUNET_break (0);
473
474   /*  struct Plugin *plugin = cls; */
475   return bytes_sent;
476 }
477
478
479
480 /**
481  * Function that can be used to force the plugin to disconnect
482  * from the given peer and cancel all previous transmissions
483  * (and their continuationc).
484  *
485  * @param cls closure
486  * @param target peer from which to disconnect
487  */
488 static void
489 http_server_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
490 {
491   // struct Plugin *plugin = cls;
492   GNUNET_break (0);
493 }
494
495
496 /**
497  * Another peer has suggested an address for this
498  * peer and transport plugin.  Check that this could be a valid
499  * address.  If so, consider adding it to the list
500  * of addresses.
501  *
502  * @param cls closure
503  * @param addr pointer to the address
504  * @param addrlen length of addr
505  * @return GNUNET_OK if this is a plausible address for this peer
506  *         and transport
507  */
508 static int
509 http_server_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
510 {
511   struct HTTP_Server_Plugin *plugin = cls;
512   struct HttpAddressWrapper *w = plugin->addr_head;
513
514   if ((NULL != plugin->ext_addr) && GNUNET_YES == (http_common_cmp_addresses (addr, addrlen, plugin->ext_addr, plugin->ext_addr_len)))
515     return GNUNET_OK;
516
517   while (NULL != w)
518   {
519     if (GNUNET_YES == (http_common_cmp_addresses(addr,
520                                                  addrlen,
521                                                  w->addr,
522                                                  w->addrlen)))
523       return GNUNET_OK;
524   }
525
526   return GNUNET_NO;
527 }
528
529 /**
530  * Creates a new outbound session the transport
531  * service will use to send data to the peer
532  *
533  * Since HTTP/S server cannot create sessions, always return NULL
534  *
535  * @param cls the plugin
536  * @param address the address
537  * @return always NULL
538  */
539 static struct Session *
540 http_server_plugin_get_session (void *cls,
541                                 const struct GNUNET_HELLO_Address *address)
542 {
543   return NULL;
544 }
545
546
547 /**
548  * Deleting the session
549  * Must not be used afterwards
550  */
551
552 void
553 server_delete_session (struct Session *s)
554 {
555   struct HTTP_Server_Plugin *plugin = s->plugin;
556   server_stop_session_timeout(s);
557
558   GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
559   struct HTTP_Message *msg = s->msg_head;
560   struct HTTP_Message *tmp = NULL;
561
562   while (msg != NULL)
563   {
564     tmp = msg->next;
565
566     GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
567     if (msg->transmit_cont != NULL)
568     {
569       msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
570     }
571     GNUNET_free (msg);
572     msg = tmp;
573   }
574
575   if (s->msg_tk != NULL)
576   {
577     GNUNET_SERVER_mst_destroy (s->msg_tk);
578     s->msg_tk = NULL;
579   }
580   GNUNET_free (s->addr);
581   GNUNET_free_non_null (s->server_recv);
582   GNUNET_free_non_null (s->server_send);
583   GNUNET_free (s);
584 }
585
586 int
587 server_disconnect (struct Session *s)
588 {
589   struct ServerConnection * send;
590   struct ServerConnection * recv;
591
592   send = (struct ServerConnection *) s->server_send;
593   if (s->server_send != NULL)
594   {
595     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
596                      "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
597                      s, s->server_send, GNUNET_i2s (&s->target));
598
599     send->disconnect = GNUNET_YES;
600 #if MHD_VERSION >= 0x00090E00
601       MHD_set_connection_option (send->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT,
602                                  1);
603 #endif
604   }
605
606   recv = (struct ServerConnection *) s->server_recv;
607   if (recv != NULL)
608   {
609     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
610                      "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
611                      s, s->server_recv, GNUNET_i2s (&s->target));
612
613     recv->disconnect = GNUNET_YES;
614 #if MHD_VERSION >= 0x00090E00
615       MHD_set_connection_option (recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT,
616                                  1);
617 #endif
618   }
619
620   /* Schedule connection immediately */
621 #if 0
622   if (s->addrlen == sizeof (struct IPv4HttpAddress))
623   {
624     server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES);
625   }
626   else if (s->addrlen == sizeof (struct IPv6HttpAddress))
627   {
628     server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES);
629   }
630 #endif
631   return GNUNET_OK;
632
633 }
634
635
636 /**
637 * Cancel timeout
638 */
639 static void
640 server_stop_session_timeout (struct Session *s)
641 {
642  GNUNET_assert (NULL != s);
643
644  if (GNUNET_SCHEDULER_NO_TASK != s->timeout_task)
645  {
646    GNUNET_SCHEDULER_cancel (s->timeout_task);
647    s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
648    GNUNET_log (TIMEOUT_LOG, "Timeout stopped for session %p\n", s);
649  }
650 }
651
652 /**
653  * Function that queries MHD's select sets and
654  * starts the task waiting for them.
655  * @param plugin plugin
656  * @param daemon_handle the MHD daemon handle
657  * @return gnunet task identifier
658  */
659 static GNUNET_SCHEDULER_TaskIdentifier
660 server_schedule (struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *daemon_handle,
661                  int now);
662
663 /**
664  * Reschedule the execution of both IPv4 and IPv6 server
665  * @param plugin the plugin
666  * @param server which server to schedule v4 or v6?
667  * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait
668  * until timeout
669  */
670 static void
671 server_reschedule (struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *server, int now)
672 {
673   if ((server == plugin->server_v4) && (plugin->server_v4 != NULL))
674   {
675     if (GNUNET_YES == plugin->server_v4_immediately)
676       return; /* No rescheduling, server will run asap */
677
678     if (GNUNET_YES == now)
679       plugin->server_v4_immediately = GNUNET_YES;
680
681     if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
682     {
683       GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
684       plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
685     }
686     plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now);
687   }
688
689   if ((server == plugin->server_v6) && (plugin->server_v6 != NULL))
690   {
691     if (GNUNET_YES == plugin->server_v6_immediately)
692       return; /* No rescheduling, server will run asap */
693
694     if (GNUNET_YES == now)
695       plugin->server_v6_immediately = GNUNET_YES;
696
697     if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
698     {
699       GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
700       plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
701     }
702     plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now);
703   }
704 }
705
706
707 static struct ServerConnection *
708 server_lookup_connection (struct HTTP_Server_Plugin *plugin,
709                        struct MHD_Connection *mhd_connection, const char *url,
710                        const char *method)
711 {
712   struct Session *s = NULL;
713   struct Session *t;
714   struct ServerConnection *sc = NULL;
715   const union MHD_ConnectionInfo *conn_info;
716   struct GNUNET_ATS_Information ats;
717
718   char *addr;
719   size_t addr_len;
720
721   struct GNUNET_PeerIdentity target;
722   uint32_t tag = 0;
723   int direction = GNUNET_SYSERR;
724
725   /* url parsing variables */
726   size_t url_len;
727   char *url_end;
728   char *hash_start;
729   char *hash_end;
730   char *tag_start;
731   char *tag_end;
732
733   conn_info = MHD_get_connection_info (mhd_connection,
734                                        MHD_CONNECTION_INFO_CLIENT_ADDRESS);
735   if ((conn_info->client_addr->sa_family != AF_INET) &&
736       (conn_info->client_addr->sa_family != AF_INET6))
737     return NULL;
738
739   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
740                    "New %s connection from %s\n", method, url);
741   /* URL parsing
742    * URL is valid if it is in the form [peerid[103];tag]*/
743   url_len = strlen (url);
744   url_end = (char *) &url[url_len];
745
746   if (url_len < 105)
747   {
748     GNUNET_break (0);
749     goto error; /* too short */
750   }
751   hash_start = strrchr (url, '/');
752   if (NULL == hash_start)
753   {
754       GNUNET_break (0);
755     goto error; /* '/' delimiter not found */
756   }
757   if (hash_start >= url_end)
758   {
759       GNUNET_break (0);
760     goto error; /* mal formed */
761   }
762   hash_start++;
763
764   hash_end = strrchr (hash_start, ';');
765   if (NULL == hash_end)
766     goto error; /* ';' delimiter not found */
767   if (hash_end >= url_end)
768   {
769       GNUNET_break (0);
770     goto error; /* mal formed */
771   }
772
773   if (hash_start >= hash_end)
774   {
775       GNUNET_break (0);
776     goto error; /* mal formed */
777   }
778
779   if ((strlen(hash_start) - strlen(hash_end)) != 103)
780   {
781       GNUNET_break (0);
782     goto error; /* invalid hash length */
783   }
784
785   char hash[104];
786   memcpy (hash, hash_start, 103);
787   hash[103] = '\0';
788   if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((const char *) hash, &(target.hashPubKey)))
789   {
790       GNUNET_break (0);
791     goto error; /* mal formed */
792   }
793
794   if (hash_end >= url_end)
795   {
796       GNUNET_break (0);
797     goto error; /* mal formed */
798   }
799
800   tag_start = &hash_end[1];
801   /* Converting tag */
802   tag_end = NULL;
803   tag = strtoul (tag_start, &tag_end, 10);
804   if (tag == 0)
805   {
806     goto error; /* mal formed */
807   }
808   if (tag_end == NULL)
809   {
810     goto error; /* mal formed */
811   }
812   if (tag_end != url_end)
813   {
814     goto error; /* mal formed */
815   }
816
817   if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
818     direction = _RECEIVE;
819   else if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
820     direction = _SEND;
821   else
822   {
823     goto error;
824   }
825
826   plugin->cur_connections++;
827   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
828                    "New %s connection from %s with tag %u (%u of %u)\n",
829                    method,
830                    GNUNET_i2s (&target), tag,
831                    plugin->cur_connections, plugin->max_connections);
832
833   /* find duplicate session */
834   t = plugin->head;
835   while (t != NULL)
836   {
837     if ((t->inbound) &&
838         (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity)))
839         &&
840         /* FIXME add source address comparison */
841         (t->tag == tag))
842       break;
843     t = t->next;
844   }
845   if (t != NULL)
846   {
847     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
848                      "Duplicate session, dismissing new connection from peer `%s'\n",
849                      GNUNET_i2s (&target));
850     goto error;
851   }
852
853   /* find semi-session */
854   t = plugin->server_semi_head;
855
856   while (t != NULL)
857   {
858     /* FIXME add source address comparison */
859     if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity)))
860         && (t->tag == tag))
861     {
862       break;
863     }
864     t = t->next;
865   }
866
867   if (t == NULL)
868     goto create;
869   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
870                    "Found existing semi-session for `%s'\n",
871                    GNUNET_i2s (&target));
872
873   if ((direction == _SEND) && (t->server_send != NULL))
874   {
875     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
876                      "Duplicate GET session, dismissing new connection from peer `%s'\n",
877                      GNUNET_i2s (&target));
878     goto error;
879   }
880   else
881   {
882     s = t;
883     GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head,
884                                  plugin->server_semi_tail, s);
885     GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
886     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
887                      "Found matching semi-session, merging session for peer `%s'\n",
888                      GNUNET_i2s (&target));
889     GNUNET_assert (NULL != s);
890     goto found;
891   }
892   if ((direction == _RECEIVE) && (t->server_recv != NULL))
893   {
894     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
895                      "Duplicate PUT session, dismissing new connection from peer `%s'\n",
896                      GNUNET_i2s (&target));
897     goto error;
898   }
899   else
900   {
901     s = t;
902     GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head,
903                                  plugin->server_semi_tail, s);
904     GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
905     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
906                      "Found matching semi-session, merging session for peer `%s'\n",
907                      GNUNET_i2s (&target));
908     GNUNET_assert (NULL != s);
909     goto found;
910   }
911
912 create:
913 /* create new session */
914
915   switch (conn_info->client_addr->sa_family)
916   {
917   case (AF_INET):
918     addr = http_common_address_from_socket (plugin->protocol, conn_info->client_addr, sizeof (struct sockaddr_in));
919     addr_len = http_common_address_get_size (addr);
920     ats = plugin->env->get_address_type (plugin->env->cls, conn_info->client_addr, sizeof (struct sockaddr_in));
921     break;
922   case (AF_INET6):
923     addr = http_common_address_from_socket (plugin->protocol, conn_info->client_addr, sizeof (struct sockaddr_in6));
924     addr_len = http_common_address_get_size (addr);
925     ats = plugin->env->get_address_type (plugin->env->cls, conn_info->client_addr, sizeof (struct sockaddr_in6));
926     break;
927   default:
928     GNUNET_break (0);
929     goto error;
930   }
931
932   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
933                    "Creating new session for peer `%s' connecting from `%s'\n",
934                    GNUNET_i2s (&target),
935                    http_common_plugin_address_to_string (NULL, addr, addr_len));
936
937   s = GNUNET_malloc (sizeof (struct Session));
938   memcpy (&s->target, &target, sizeof (struct GNUNET_PeerIdentity));
939   s->plugin = plugin;
940   s->addr = addr;
941   s->addrlen = addr_len;
942   s->ats_address_network_type = ats.value;
943   s->inbound = GNUNET_YES;
944   s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS;
945   s->tag = tag;
946   s->server_recv = NULL;
947   s->server_send = NULL;
948
949   server_start_session_timeout(s);
950
951   GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head,
952                                plugin->server_semi_tail, s);
953   goto found;
954 error:
955   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
956                    "Invalid connection request\n");
957   return NULL;
958
959 found:
960
961   sc = GNUNET_malloc (sizeof (struct ServerConnection));
962
963   if (conn_info->client_addr->sa_family == AF_INET)
964     sc->mhd_daemon = plugin->server_v4;
965   if (conn_info->client_addr->sa_family == AF_INET6)
966     sc->mhd_daemon = plugin->server_v6;
967   sc->mhd_conn = mhd_connection;
968   sc->direction = direction;
969   sc->session = s;
970   if (direction == _SEND)
971     s->server_send = sc;
972   if (direction == _RECEIVE)
973     s->server_recv = sc;
974
975 #if MHD_VERSION >= 0x00090E00
976   int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000);
977
978   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
979                    "Setting timeout for %p to %u sec.\n", sc, to);
980   MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to);
981
982   server_reschedule (plugin, sc->mhd_daemon, GNUNET_NO);
983 #endif
984   return sc;
985
986 }
987
988 static struct Session *
989 server_lookup_session (struct HTTP_Server_Plugin *plugin,
990                        struct ServerConnection * sc)
991 {
992   struct Session *s;
993
994   for (s = plugin->head; NULL != s; s = s->next)
995     if ((s->server_recv == sc) || (s->server_send == sc))
996       return s;
997   for (s = plugin->server_semi_head; NULL != s; s = s->next)
998     if ((s->server_recv == sc) || (s->server_send == sc))
999       return s;
1000   return NULL;
1001 }
1002
1003 int
1004 server_exist_session (struct HTTP_Server_Plugin *plugin, struct Session *s)
1005 {
1006   struct Session * head;
1007
1008   GNUNET_assert (NULL != plugin);
1009   GNUNET_assert (NULL != s);
1010
1011   for (head = plugin->head; head != NULL; head = head->next)
1012   {
1013     if (head == s)
1014       return GNUNET_YES;
1015   }
1016   return GNUNET_NO;
1017 }
1018
1019
1020 /**
1021  * Callback called by MHD when it needs data to send
1022  * @param cls current session
1023  * @param pos position in buffer
1024  * @param buf the buffer to write data to
1025  * @param max max number of bytes available in buffer
1026  * @return bytes written to buffer
1027  */
1028 static ssize_t
1029 server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
1030 {
1031   struct Session *s = cls;
1032   ssize_t bytes_read = 0;
1033   struct HTTP_Message *msg;
1034
1035   GNUNET_assert (NULL != p);
1036   if (GNUNET_NO == server_exist_session (p, s))
1037     return 0;
1038   msg = s->msg_head;
1039   if (NULL != msg)
1040   {
1041     /* sending */
1042     bytes_read = GNUNET_MIN (msg->size - msg->pos,
1043                              max);
1044     memcpy (buf, &msg->buf[msg->pos], bytes_read);
1045     msg->pos += bytes_read;
1046
1047     /* removing message */
1048     if (msg->pos == msg->size)
1049     {
1050       GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
1051       if (NULL != msg->transmit_cont)
1052         msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK);
1053       GNUNET_free (msg);
1054     }
1055   }
1056   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
1057                    "Sent %u bytes\n", s, bytes_read);
1058   return bytes_read;
1059 }
1060
1061 /**
1062  * Callback called by MessageStreamTokenizer when a message has arrived
1063  * @param cls current session as closure
1064  * @param client clien
1065  * @param message the message to be forwarded to transport service
1066  */
1067 static int
1068 server_receive_mst_cb (void *cls, void *client,
1069                        const struct GNUNET_MessageHeader *message)
1070 {
1071   struct Session *s = cls;
1072   struct GNUNET_ATS_Information atsi[2];
1073   struct GNUNET_TIME_Relative delay;
1074
1075   GNUNET_assert (NULL != p);
1076   if (GNUNET_NO == server_exist_session(p, s))
1077     return GNUNET_OK;
1078
1079   struct HTTP_Server_Plugin *plugin = s->plugin;
1080
1081   atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
1082   atsi[0].value = htonl (1);
1083   atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
1084   atsi[1].value = s->ats_address_network_type;
1085   GNUNET_break (s->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED));
1086
1087   delay = plugin->env->receive (plugin->env->cls,
1088                                 &s->target,
1089                                 message,
1090                                 (const struct GNUNET_ATS_Information *) &atsi, 2,
1091                                 s, s->addr, s->addrlen);
1092
1093   s->next_receive =
1094       GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay);
1095   if (delay.rel_value > 0)
1096   {
1097     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1098                      "Server: peer `%s' address `%s' next read delayed for %llu ms\n",
1099                      GNUNET_i2s (&s->target),
1100                      http_common_plugin_address_to_string (NULL, s->addr, s->addrlen),
1101                      delay);
1102   }
1103   server_reschedule_session_timeout (s);
1104   return GNUNET_OK;
1105 }
1106
1107
1108 static int
1109 server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
1110                   const char *url, const char *method, const char *version,
1111                   const char *upload_data, size_t * upload_data_size,
1112                   void **httpSessionCache)
1113 {
1114   struct HTTP_Server_Plugin *plugin = cls;
1115   int res = MHD_YES;
1116
1117   struct ServerConnection *sc = *httpSessionCache;
1118   struct Session *s;
1119   struct MHD_Response *response;
1120
1121   GNUNET_assert (cls != NULL);
1122   if (sc == NULL)
1123   {
1124     /* new connection */
1125     sc = server_lookup_connection (plugin, mhd_connection, url, method);
1126     if (sc != NULL)
1127       (*httpSessionCache) = sc;
1128     else
1129     {
1130       response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
1131       res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
1132       MHD_destroy_response (response);
1133       return res;
1134     }
1135   }
1136   else
1137   {
1138     /* 'old' connection */
1139     if (NULL == server_lookup_session (plugin, sc))
1140     {
1141       /* Session was already disconnected */
1142       return MHD_NO;
1143     }
1144   }
1145
1146   /* existing connection */
1147   sc = (*httpSessionCache);
1148   s = sc->session;
1149
1150   GNUNET_assert (NULL != s);
1151   /* connection is to be disconnected */
1152   if (sc->disconnect == GNUNET_YES)
1153   {
1154     /* Sent HTTP/1.1: 200 OK as PUT Response\ */
1155     response =
1156         MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!",
1157                                        MHD_NO, MHD_NO);
1158     res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1159     MHD_destroy_response (response);
1160     return MHD_YES;
1161   }
1162
1163   GNUNET_assert (s != NULL);
1164   /* Check if both directions are connected */
1165   if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL))
1166   {
1167     /* Delayed read from since not both semi-connections are connected */
1168     return MHD_YES;
1169   }
1170
1171   if (sc->direction == _SEND)
1172   {
1173     response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
1174                                                   32 * 1024,
1175                                                   &server_send_callback, s,
1176                                                   NULL);
1177     MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1178     MHD_destroy_response (response);
1179     return MHD_YES;
1180   }
1181   if (sc->direction == _RECEIVE)
1182   {
1183     if (*upload_data_size == 0)
1184     {
1185       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1186                        "Peer `%s' PUT on address `%s' connected\n",
1187                        GNUNET_i2s (&s->target),
1188                        http_common_plugin_address_to_string (NULL,
1189                                                              s->addr,
1190                                                              s->addrlen));
1191       return MHD_YES;
1192     }
1193
1194     /* Receiving data */
1195     if ((*upload_data_size > 0))
1196     {
1197       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1198                        "Peer `%s' PUT on address `%s' received %u bytes\n",
1199                        GNUNET_i2s (&s->target),
1200                        http_common_plugin_address_to_string (NULL,
1201                                                              s->addr,
1202                                                              s->addrlen),
1203                        *upload_data_size);
1204       struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1205
1206       if ((s->next_receive.abs_value <= now.abs_value))
1207       {
1208         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1209                          "PUT with %u bytes forwarded to MST\n", s,
1210                          *upload_data_size);
1211         if (s->msg_tk == NULL)
1212         {
1213           s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s);
1214         }
1215             GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data,
1216                                        *upload_data_size, GNUNET_NO, GNUNET_NO);
1217
1218 #if MHD_VERSION >= 0x00090E00
1219         int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000);
1220         struct ServerConnection *t = NULL;
1221
1222         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1223                          "Received %u bytes\n", *upload_data_size);
1224         /* Setting timeouts for other connections */
1225         if (s->server_recv != NULL)
1226         {
1227           t = s->server_recv;
1228           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1229                            "Setting timeout for %p to %u sec.\n", t,
1230                            to);
1231           MHD_set_connection_option (t->mhd_conn,
1232                                      MHD_CONNECTION_OPTION_TIMEOUT,
1233                                      to);
1234           server_reschedule (plugin, t->mhd_daemon, GNUNET_NO);
1235         }
1236         if (s->server_send != NULL)
1237         {
1238           t = s->server_send;
1239           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1240                            "Setting timeout for %p to %u sec.\n", t,
1241                            to);
1242           MHD_set_connection_option (t->mhd_conn,
1243                                      MHD_CONNECTION_OPTION_TIMEOUT,
1244                                      to);
1245           server_reschedule (plugin, t->mhd_daemon, GNUNET_NO);
1246         }
1247 #endif
1248         (*upload_data_size) = 0;
1249       }
1250       else
1251       {
1252         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1253                     "Server: %p no inbound bandwidth available! Next read was delayed by %llu ms\n",
1254                     s, now.abs_value - s->next_receive.abs_value);
1255       }
1256       return MHD_YES;
1257     }
1258     else
1259       return MHD_NO;
1260   }
1261   return res;
1262 }
1263
1264 static void
1265 server_disconnect_cb (void *cls, struct MHD_Connection *connection,
1266                       void **httpSessionCache)
1267 {
1268   /* FIXME SPLIT */
1269   GNUNET_break (0);
1270 }
1271
1272 /**
1273  * Check if incoming connection is accepted.
1274  * NOTE: Here every connection is accepted
1275  * @param cls plugin as closure
1276  * @param addr address of incoming connection
1277  * @param addr_len address length of incoming connection
1278  * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
1279  *
1280  */
1281 static int
1282 server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len)
1283 {
1284   struct HTTP_Server_Plugin *plugin = cls;
1285
1286   if (plugin->cur_connections <= plugin->max_connections)
1287     return MHD_YES;
1288   else
1289   {
1290     GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
1291                      _("Server reached maximum number connections (%u), rejecting new connection\n"),
1292                      plugin->max_connections);
1293     return MHD_NO;
1294   }
1295 }
1296
1297 static void
1298 server_log (void *arg, const char *fmt, va_list ap)
1299 {
1300   char text[1024];
1301
1302   vsnprintf (text, sizeof (text), fmt, ap);
1303   va_end (ap);
1304   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text);
1305 }
1306
1307
1308 /**
1309  * Call MHD IPv4 to process pending requests and then go back
1310  * and schedule the next run.
1311  * @param cls plugin as closure
1312  * @param tc task context
1313  */
1314 static void
1315 server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1316 {
1317   struct HTTP_Server_Plugin *plugin = cls;
1318
1319   GNUNET_assert (cls != NULL);
1320
1321   plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
1322   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1323     return;
1324 #if 0
1325   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1326                    "Running IPv4 server\n");
1327 #endif
1328   plugin->server_v4_immediately = GNUNET_NO;
1329   GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
1330   server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
1331 }
1332
1333
1334 /**
1335  * Call MHD IPv6 to process pending requests and then go back
1336  * and schedule the next run.
1337  * @param cls plugin as closure
1338  * @param tc task context
1339  */
1340 static void
1341 server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1342 {
1343   struct HTTP_Server_Plugin *plugin = cls;
1344
1345   GNUNET_assert (cls != NULL);
1346   plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
1347   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1348     return;
1349 #if 0
1350   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1351                    "Running IPv6 server\n");
1352 #endif
1353   plugin->server_v6_immediately = GNUNET_NO;
1354   GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
1355   server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
1356 }
1357
1358
1359 /**
1360  * Function that queries MHD's select sets and
1361  * starts the task waiting for them.
1362  * @param plugin plugin
1363  * @param daemon_handle the MHD daemon handle
1364  * @return gnunet task identifier
1365  */
1366 static GNUNET_SCHEDULER_TaskIdentifier
1367 server_schedule (struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *daemon_handle,
1368                  int now)
1369 {
1370   GNUNET_SCHEDULER_TaskIdentifier ret;
1371   fd_set rs;
1372   fd_set ws;
1373   fd_set es;
1374   struct GNUNET_NETWORK_FDSet *wrs;
1375   struct GNUNET_NETWORK_FDSet *wws;
1376   struct GNUNET_NETWORK_FDSet *wes;
1377   int max;
1378   unsigned MHD_LONG_LONG timeout;
1379   static unsigned long long last_timeout = 0;
1380   int haveto;
1381
1382   struct GNUNET_TIME_Relative tv;
1383
1384   ret = GNUNET_SCHEDULER_NO_TASK;
1385   FD_ZERO (&rs);
1386   FD_ZERO (&ws);
1387   FD_ZERO (&es);
1388   wrs = GNUNET_NETWORK_fdset_create ();
1389   wes = GNUNET_NETWORK_fdset_create ();
1390   wws = GNUNET_NETWORK_fdset_create ();
1391   max = -1;
1392   GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
1393   haveto = MHD_get_timeout (daemon_handle, &timeout);
1394   if (haveto == MHD_YES)
1395   {
1396     if (timeout != last_timeout)
1397     {
1398 #if VERBOSE_SERVER
1399       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1400                        "SELECT Timeout changed from %llu to %llu\n",
1401                        last_timeout, timeout);
1402 #endif
1403       last_timeout = timeout;
1404     }
1405     tv.rel_value = (uint64_t) timeout;
1406   }
1407   else
1408     tv = GNUNET_TIME_UNIT_SECONDS;
1409   /* Force immediate run, since we have outbound data to send */
1410   if (now == GNUNET_YES)
1411     tv = GNUNET_TIME_UNIT_MILLISECONDS;
1412   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1413   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1414   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
1415
1416   if (daemon_handle == plugin->server_v4)
1417   {
1418     if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
1419     {
1420       GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1421       plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
1422     }
1423 #if 0
1424     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1425                      "Scheduling IPv4 server task in %llu ms\n", tv);
1426 #endif
1427     ret =
1428         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1429                                      tv, wrs, wws,
1430                                      &server_v4_run, plugin);
1431   }
1432   if (daemon_handle == plugin->server_v6)
1433   {
1434     if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
1435     {
1436       GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1437       plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
1438     }
1439 #if 0
1440     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1441                      "Scheduling IPv6 server task in %llu ms\n", tv);
1442 #endif
1443     ret =
1444         GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1445                                      tv, wrs, wws,
1446                                      &server_v6_run, plugin);
1447   }
1448   GNUNET_NETWORK_fdset_destroy (wrs);
1449   GNUNET_NETWORK_fdset_destroy (wws);
1450   GNUNET_NETWORK_fdset_destroy (wes);
1451   return ret;
1452 }
1453
1454
1455 #if BUILD_HTTPS
1456 static char *
1457 server_load_file (const char *file)
1458 {
1459   struct GNUNET_DISK_FileHandle *gn_file;
1460   uint64_t fsize;
1461   char *text = NULL;
1462
1463   if (GNUNET_OK != GNUNET_DISK_file_size (file,
1464       &fsize, GNUNET_NO, GNUNET_YES))
1465     return NULL;
1466   text = GNUNET_malloc (fsize + 1);
1467   gn_file =
1468       GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
1469                              GNUNET_DISK_PERM_USER_READ);
1470   if (gn_file == NULL)
1471   {
1472     GNUNET_free (text);
1473     return NULL;
1474   }
1475   if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize))
1476   {
1477     GNUNET_free (text);
1478     GNUNET_DISK_file_close (gn_file);
1479     return NULL;
1480   }
1481   text[fsize] = '\0';
1482   GNUNET_DISK_file_close (gn_file);
1483   return text;
1484 }
1485 #endif
1486
1487
1488 #if BUILD_HTTPS
1489
1490 static int
1491 server_load_certificate (struct HTTP_Server_Plugin *plugin)
1492 {
1493   int res = GNUNET_OK;
1494
1495   char *key_file;
1496   char *cert_file;
1497
1498   /* Get crypto init string from config
1499    * If not present just use default values */
1500
1501   if (GNUNET_OK ==
1502                  GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
1503                                                         plugin->name,
1504                                                         "CRYPTO_INIT",
1505                                                         &plugin->crypto_init))
1506       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1507                        "Using crypto init string `%s'\n",
1508                        plugin->crypto_init);
1509   else
1510     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1511                      "Using default crypto init string \n");
1512
1513   if (GNUNET_OK !=
1514       GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
1515                                                "KEY_FILE", &key_file))
1516   {
1517     key_file = GNUNET_strdup ("https_key.key");
1518   }
1519
1520   if (GNUNET_OK !=
1521       GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
1522                                                "CERT_FILE", &cert_file))
1523   {
1524     GNUNET_asprintf (&cert_file, "%s", "https_cert.crt");
1525   }
1526
1527   /* read key & certificates from file */
1528   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1529               "Trying to loading TLS certificate from key-file `%s' cert-file`%s'\n",
1530               key_file, cert_file);
1531
1532   plugin->key = server_load_file (key_file);
1533   plugin->cert = server_load_file (cert_file);
1534
1535   if ((plugin->key == NULL) || (plugin->cert == NULL))
1536   {
1537     struct GNUNET_OS_Process *cert_creation;
1538
1539     GNUNET_free_non_null (plugin->key);
1540     plugin->key = NULL;
1541     GNUNET_free_non_null (plugin->cert);
1542     plugin->cert = NULL;
1543
1544     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1545                 "No usable TLS certificate found, creating certificate\n");
1546     errno = 0;
1547     cert_creation =
1548         GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL,
1549                                  "gnunet-transport-certificate-creation",
1550                                  "gnunet-transport-certificate-creation",
1551                                  key_file, cert_file, NULL);
1552     if (cert_creation == NULL)
1553     {
1554       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1555                        _
1556                        ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
1557       GNUNET_free (key_file);
1558       GNUNET_free (cert_file);
1559
1560       GNUNET_free_non_null (plugin->key);
1561       plugin->key = NULL;
1562       GNUNET_free_non_null (plugin->cert);
1563       plugin->cert = NULL;
1564       GNUNET_free_non_null (plugin->crypto_init);
1565       plugin->crypto_init = NULL;
1566
1567       return GNUNET_SYSERR;
1568     }
1569     GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
1570     GNUNET_OS_process_destroy (cert_creation);
1571
1572     plugin->key = server_load_file (key_file);
1573     plugin->cert = server_load_file (cert_file);
1574   }
1575
1576   if ((plugin->key == NULL) || (plugin->cert == NULL))
1577   {
1578     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1579                      _
1580                      ("No usable TLS certificate found and creating one failed!\n"),
1581                      "transport-https");
1582     GNUNET_free (key_file);
1583     GNUNET_free (cert_file);
1584
1585     GNUNET_free_non_null (plugin->key);
1586     plugin->key = NULL;
1587     GNUNET_free_non_null (plugin->cert);
1588     plugin->cert = NULL;
1589     GNUNET_free_non_null (plugin->crypto_init);
1590     plugin->crypto_init = NULL;
1591
1592     return GNUNET_SYSERR;
1593   }
1594   GNUNET_free (key_file);
1595   GNUNET_free (cert_file);
1596   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n");
1597   return res;
1598 }
1599 #endif
1600
1601 int
1602 server_start (struct HTTP_Server_Plugin *plugin)
1603 {
1604   unsigned int timeout;
1605   GNUNET_assert (NULL != plugin);
1606
1607 #if BUILD_HTTPS
1608   if (GNUNET_SYSERR == server_load_certificate (plugin))
1609   {
1610     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1611                      "Could not load or create server certificate! Loading plugin failed!\n");
1612     return GNUNET_SYSERR;
1613   }
1614 #endif
1615
1616
1617 #if MHD_VERSION >= 0x00090E00
1618   timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000;
1619   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1620                    "MHD can set timeout per connection! Default time out %u sec.\n",
1621                    timeout);
1622 #else
1623   timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000;
1624   GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
1625                    "MHD cannot set timeout per connection! Default time out %u sec.\n",
1626                    timeout);
1627 #endif
1628   plugin->server_v4 = NULL;
1629   if (plugin->use_ipv4 == GNUNET_YES)
1630   {
1631     plugin->server_v4 = MHD_start_daemon (
1632 #if VERBOSE_SERVER
1633                                            MHD_USE_DEBUG |
1634 #endif
1635 #if BUILD_HTTPS
1636                                            MHD_USE_SSL |
1637 #endif
1638                                            MHD_NO_FLAG, plugin->port,
1639                                            &server_accept_cb, plugin,
1640                                            &server_access_cb, plugin,
1641                                            MHD_OPTION_SOCK_ADDR,
1642                                            (struct sockaddr_in *)
1643                                            plugin->server_addr_v4,
1644                                            MHD_OPTION_CONNECTION_LIMIT,
1645                                            (unsigned int)
1646                                            plugin->max_connections,
1647 #if BUILD_HTTPS
1648                                            MHD_OPTION_HTTPS_PRIORITIES,
1649                                            plugin->crypto_init,
1650                                            MHD_OPTION_HTTPS_MEM_KEY,
1651                                            plugin->key,
1652                                            MHD_OPTION_HTTPS_MEM_CERT,
1653                                            plugin->cert,
1654 #endif
1655                                            MHD_OPTION_CONNECTION_TIMEOUT,
1656                                            timeout,
1657                                            MHD_OPTION_CONNECTION_MEMORY_LIMIT,
1658                                            (size_t) (2 *
1659                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE),
1660                                            MHD_OPTION_NOTIFY_COMPLETED,
1661                                            &server_disconnect_cb, plugin,
1662                                            MHD_OPTION_EXTERNAL_LOGGER,
1663                                            server_log, NULL, MHD_OPTION_END);
1664   }
1665   plugin->server_v6 = NULL;
1666   if (plugin->use_ipv6 == GNUNET_YES)
1667   {
1668     plugin->server_v6 = MHD_start_daemon (
1669 #if VERBOSE_SERVER
1670                                            MHD_USE_DEBUG |
1671 #endif
1672 #if BUILD_HTTPS
1673                                            MHD_USE_SSL |
1674 #endif
1675                                            MHD_USE_IPv6, plugin->port,
1676                                            &server_accept_cb, plugin,
1677                                            &server_access_cb, plugin,
1678                                            MHD_OPTION_SOCK_ADDR,
1679                                            (struct sockaddr_in6 *)
1680                                            plugin->server_addr_v6,
1681                                            MHD_OPTION_CONNECTION_LIMIT,
1682                                            (unsigned int)
1683                                            plugin->max_connections,
1684 #if BUILD_HTTPS
1685                                            MHD_OPTION_HTTPS_PRIORITIES,
1686                                            plugin->crypto_init,
1687                                            MHD_OPTION_HTTPS_MEM_KEY,
1688                                            plugin->key,
1689                                            MHD_OPTION_HTTPS_MEM_CERT,
1690                                            plugin->cert,
1691 #endif
1692                                            MHD_OPTION_CONNECTION_TIMEOUT,
1693                                            timeout,
1694                                            MHD_OPTION_CONNECTION_MEMORY_LIMIT,
1695                                            (size_t) (2 *
1696                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE),
1697                                            MHD_OPTION_NOTIFY_COMPLETED,
1698                                            &server_disconnect_cb, plugin,
1699                                            MHD_OPTION_EXTERNAL_LOGGER,
1700                                            server_log, NULL, MHD_OPTION_END);
1701
1702   }
1703
1704   if ((plugin->use_ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL))
1705   {
1706     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1707                      "Failed to start %s IPv4 server component on port %u\n",
1708                      plugin->name, plugin->port);
1709     return GNUNET_SYSERR;
1710   }
1711   server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
1712
1713   if ((plugin->use_ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL))
1714   {
1715     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
1716                      "Failed to start %s IPv6 server component on port %u\n",
1717                      plugin->name, plugin->port);
1718     return GNUNET_SYSERR;
1719   }
1720   server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
1721   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1722                    "%s server component started on port %u\n", plugin->name,
1723                    plugin->port);
1724   return GNUNET_OK;
1725 }
1726
1727
1728 void
1729 server_stop (struct HTTP_Server_Plugin *plugin)
1730 {
1731   struct Session *s = NULL;
1732   struct Session *t = NULL;
1733
1734   struct MHD_Daemon *server_v4_tmp = plugin->server_v4;
1735   plugin->server_v4 = NULL;
1736
1737   struct MHD_Daemon *server_v6_tmp = plugin->server_v6;
1738   plugin->server_v6 = NULL;
1739
1740   if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
1741   {
1742     GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1743     plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
1744   }
1745
1746   if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
1747   {
1748     GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1749     plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
1750   }
1751
1752   if (server_v6_tmp != NULL)
1753   {
1754     MHD_stop_daemon (server_v4_tmp);
1755   }
1756   if (server_v6_tmp != NULL)
1757   {
1758     MHD_stop_daemon (server_v6_tmp);
1759   }
1760
1761   /* cleaning up semi-sessions never propagated */
1762   s = plugin->server_semi_head;
1763   while (s != NULL)
1764   {
1765 #if VERBOSE_SERVER
1766     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1767                      "Deleting semi-sessions %p\n", s);
1768 #endif
1769     t = s->next;
1770     struct HTTP_Message *msg = s->msg_head;
1771     struct HTTP_Message *tmp = NULL;
1772
1773     while (msg != NULL)
1774     {
1775       tmp = msg->next;
1776
1777       GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
1778       if (msg->transmit_cont != NULL)
1779       {
1780         msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
1781       }
1782       GNUNET_free (msg);
1783       msg = tmp;
1784     }
1785
1786     server_delete_session (s);
1787     s = t;
1788   }
1789
1790   p = NULL;
1791
1792 #if BUILD_HTTPS
1793   GNUNET_free_non_null (plugin->crypto_init);
1794   GNUNET_free_non_null (plugin->cert);
1795   GNUNET_free_non_null (plugin->key);
1796 #endif
1797
1798   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1799                    "%s server component stopped\n", plugin->name);
1800 }
1801
1802 static void
1803 server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
1804                  socklen_t addrlen)
1805 {
1806   struct HTTP_Server_Plugin *plugin = cls;
1807   struct HttpAddressWrapper *w = NULL;
1808
1809   if ((AF_INET == addr->sa_family) && (GNUNET_NO == plugin->use_ipv4))
1810     return;
1811
1812   if ((AF_INET6 == addr->sa_family) && (GNUNET_NO == plugin->use_ipv6))
1813     return;
1814
1815   w = GNUNET_malloc (sizeof (struct HttpAddressWrapper));
1816   w->addr = http_common_address_from_socket (plugin->protocol, addr, addrlen);
1817   if (NULL == w->addr)
1818   {
1819     GNUNET_free (w);
1820     return;
1821   }
1822   w->addrlen = http_common_address_get_size (w->addr);
1823
1824   GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w);
1825   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1826                    "Notifying transport to add address `%s'\n",
1827                    http_common_plugin_address_to_string(NULL, w->addr, w->addrlen));
1828
1829   plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, w->addrlen);
1830 }
1831
1832
1833 static void
1834 server_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
1835                     socklen_t addrlen)
1836 {
1837   struct HTTP_Server_Plugin *plugin = cls;
1838   struct HttpAddressWrapper *w = plugin->addr_head;
1839   size_t saddr_len;
1840   void * saddr = http_common_address_from_socket (plugin->protocol, addr, addrlen);
1841   if (NULL == saddr)
1842     return;
1843   saddr_len =  http_common_address_get_size (saddr);
1844
1845   while (NULL != w)
1846   {
1847       if (GNUNET_YES == http_common_cmp_addresses(w->addr, w->addrlen, saddr, saddr_len))
1848         break;
1849       w = w->next;
1850   }
1851   GNUNET_free (saddr);
1852
1853   if (NULL == w)
1854     return;
1855
1856   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1857                    "Notifying transport to remove address `%s'\n",
1858                    http_common_plugin_address_to_string (NULL, w->addr, w->addrlen));
1859   GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
1860   plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, w->addrlen);
1861   GNUNET_free (w->addr);
1862   GNUNET_free (w);
1863 }
1864
1865
1866
1867 /**
1868  * Our external IP address/port mapping has changed.
1869  *
1870  * @param cls closure, the 'struct LocalAddrList'
1871  * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
1872  *     the previous (now invalid) one
1873  * @param addr either the previous or the new public IP address
1874  * @param addrlen actual lenght of the address
1875  */
1876 static void
1877 server_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
1878                        socklen_t addrlen)
1879 {
1880   GNUNET_assert (cls != NULL);
1881   struct HTTP_Server_Plugin *plugin = cls;
1882
1883   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1884                    "NPMC called %s to address `%s'\n",
1885                    (add_remove == GNUNET_NO) ? "remove" : "add",
1886                    GNUNET_a2s (addr, addrlen));
1887
1888   switch (add_remove)
1889   {
1890   case GNUNET_YES:
1891     server_add_address (cls, add_remove, addr, addrlen);
1892     break;
1893   case GNUNET_NO:
1894     server_remove_address (cls, add_remove, addr, addrlen);
1895     break;
1896   }
1897 }
1898
1899
1900 static int
1901 server_get_addresses (struct HTTP_Server_Plugin *plugin,
1902                       const char *serviceName,
1903                       const struct GNUNET_CONFIGURATION_Handle *cfg,
1904                       struct sockaddr ***addrs, socklen_t ** addr_lens)
1905 {
1906   int disablev6;
1907   unsigned long long port;
1908   struct addrinfo hints;
1909   struct addrinfo *res;
1910   struct addrinfo *pos;
1911   struct addrinfo *next;
1912   unsigned int i;
1913   int resi;
1914   int ret;
1915   struct sockaddr **saddrs;
1916   socklen_t *saddrlens;
1917   char *hostname;
1918
1919   *addrs = NULL;
1920   *addr_lens = NULL;
1921
1922   disablev6 = !plugin->use_ipv6;
1923
1924   port = 0;
1925   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
1926   {
1927     GNUNET_break (GNUNET_OK ==
1928                   GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
1929                                                          "PORT", &port));
1930     if (port > 65535)
1931     {
1932       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1933                   _
1934                   ("Require valid port number for service in configuration!\n"));
1935       return GNUNET_SYSERR;
1936     }
1937   }
1938   if (0 == port)
1939   {
1940     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, plugin->name,
1941                      "Starting in listen only mode\n");
1942     return -1; /* listen only */
1943   }
1944
1945
1946   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
1947   {
1948     GNUNET_break (GNUNET_OK ==
1949                   GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
1950                                                          "BINDTO", &hostname));
1951   }
1952   else
1953     hostname = NULL;
1954
1955   if (hostname != NULL)
1956   {
1957     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
1958                      "Resolving `%s' since that is where `%s' will bind to.\n",
1959                      hostname, serviceName);
1960     memset (&hints, 0, sizeof (struct addrinfo));
1961     if (disablev6)
1962       hints.ai_family = AF_INET;
1963     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1964         (res == NULL))
1965     {
1966       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
1967                   hostname, gai_strerror (ret));
1968       GNUNET_free (hostname);
1969       return GNUNET_SYSERR;
1970     }
1971     next = res;
1972     i = 0;
1973     while (NULL != (pos = next))
1974     {
1975       next = pos->ai_next;
1976       if ((disablev6) && (pos->ai_family == AF_INET6))
1977         continue;
1978       i++;
1979     }
1980     if (0 == i)
1981     {
1982       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1983                   _("Failed to find %saddress for `%s'.\n"),
1984                   disablev6 ? "IPv4 " : "", hostname);
1985       freeaddrinfo (res);
1986       GNUNET_free (hostname);
1987       return GNUNET_SYSERR;
1988     }
1989     resi = i;
1990     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1991     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1992     i = 0;
1993     next = res;
1994     while (NULL != (pos = next))
1995     {
1996       next = pos->ai_next;
1997       if ((disablev6) && (pos->ai_family == AF_INET6))
1998         continue;
1999       if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
2000         continue;               /* not TCP */
2001       if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
2002         continue;               /* huh? */
2003       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2004                        "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr,
2005                                                                   pos->ai_addrlen));
2006       if (pos->ai_family == AF_INET)
2007       {
2008         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
2009         saddrlens[i] = pos->ai_addrlen;
2010         saddrs[i] = GNUNET_malloc (saddrlens[i]);
2011         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2012         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2013       }
2014       else
2015       {
2016         GNUNET_assert (pos->ai_family == AF_INET6);
2017         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
2018         saddrlens[i] = pos->ai_addrlen;
2019         saddrs[i] = GNUNET_malloc (saddrlens[i]);
2020         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2021         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2022       }
2023       i++;
2024     }
2025     GNUNET_free (hostname);
2026     freeaddrinfo (res);
2027     resi = i;
2028   }
2029   else
2030   {
2031     /* will bind against everything, just set port */
2032     if (disablev6)
2033     {
2034       /* V4-only */
2035       resi = 1;
2036       i = 0;
2037       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
2038       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
2039
2040       saddrlens[i] = sizeof (struct sockaddr_in);
2041       saddrs[i] = GNUNET_malloc (saddrlens[i]);
2042 #if HAVE_SOCKADDR_IN_SIN_LEN
2043       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
2044 #endif
2045       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2046       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2047     }
2048     else
2049     {
2050       /* dual stack */
2051       resi = 2;
2052       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
2053       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
2054       i = 0;
2055       saddrlens[i] = sizeof (struct sockaddr_in6);
2056       saddrs[i] = GNUNET_malloc (saddrlens[i]);
2057 #if HAVE_SOCKADDR_IN_SIN_LEN
2058       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
2059 #endif
2060       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
2061       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2062       i++;
2063       saddrlens[i] = sizeof (struct sockaddr_in);
2064       saddrs[i] = GNUNET_malloc (saddrlens[i]);
2065 #if HAVE_SOCKADDR_IN_SIN_LEN
2066       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
2067 #endif
2068       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2069       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2070     }
2071   }
2072   *addrs = saddrs;
2073   *addr_lens = saddrlens;
2074   return resi;
2075 }
2076
2077 static void
2078 server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
2079 {
2080   int res = GNUNET_OK;
2081   struct sockaddr **addrs;
2082   socklen_t *addrlens;
2083
2084   res = server_get_addresses (plugin,
2085                               plugin->name, plugin->env->cfg,
2086                               &addrs, &addrlens);
2087   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2088                    _("Found %u addresses to report to NAT service\n"), res);
2089
2090   if (GNUNET_SYSERR == res)
2091   {
2092     plugin->nat = NULL;
2093     return;
2094   }
2095
2096   plugin->nat =
2097       GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
2098                            (unsigned int) res,
2099                            (const struct sockaddr **) addrs, addrlens,
2100                            &server_nat_port_map_callback, NULL, plugin);
2101   while (res > 0)
2102   {
2103     res--;
2104     GNUNET_assert (addrs[res] != NULL);
2105     GNUNET_free (addrs[res]);
2106   }
2107   GNUNET_free_non_null (addrs);
2108   GNUNET_free_non_null (addrlens);
2109 }
2110
2111
2112 static void
2113 server_stop_report_addresses (struct HTTP_Server_Plugin *plugin)
2114 {
2115   /* Stop NAT handle */
2116   if (NULL != plugin->nat)
2117     GNUNET_NAT_unregister (plugin->nat);
2118
2119   /* Clean up addresses */
2120   struct HttpAddressWrapper *w;
2121
2122   while (plugin->addr_head != NULL)
2123   {
2124     w = plugin->addr_head;
2125     GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
2126     GNUNET_free (w->addr);
2127     GNUNET_free (w);
2128   }
2129 }
2130
2131
2132 /**
2133  * Check if IPv6 supported on this system
2134  */
2135 static int
2136 server_check_ipv6_support (struct HTTP_Server_Plugin *plugin)
2137 {
2138   struct GNUNET_NETWORK_Handle *desc = NULL;
2139   int res = GNUNET_NO;
2140
2141   /* Probe IPv6 support */
2142   desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
2143   if (NULL == desc)
2144   {
2145     if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
2146         (errno == EACCES))
2147     {
2148       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
2149     }
2150     GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
2151                      _
2152                      ("Disabling IPv6 since it is not supported on this system!\n"));
2153     res = GNUNET_NO;
2154   }
2155   else
2156   {
2157     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
2158     desc = NULL;
2159     res = GNUNET_YES;
2160   }
2161   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2162                    "Testing IPv6 on this system: %s\n",
2163                    (res == GNUNET_YES) ? "successful" : "failed");
2164   return res;
2165 }
2166
2167
2168 /**
2169  * Function called when the service shuts down.  Unloads our plugins
2170  * and cancels pending validations.
2171  *
2172  * @param cls closure, unused
2173  * @param tc task context (unused)
2174  */
2175 static void
2176 server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2177 {
2178   struct HTTP_Server_Plugin *plugin = cls;
2179
2180   plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
2181
2182   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2183     return;
2184
2185   GNUNET_asprintf(&plugin->ext_addr, "%s://%s", plugin->protocol, plugin->external_hostname);
2186   plugin->ext_addr_len = strlen (plugin->ext_addr) + 1;
2187   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2188                    "Notifying transport about external hostname address `%s'\n", plugin->ext_addr);
2189   plugin->env->notify_address (plugin->env->cls, GNUNET_YES, plugin->ext_addr, plugin->ext_addr_len );
2190 }
2191
2192
2193 static int
2194 server_configure_plugin (struct HTTP_Server_Plugin *plugin)
2195 {
2196   unsigned long long port;
2197   unsigned long long max_connections;
2198   char *bind4_address = NULL;
2199   char *bind6_address = NULL;
2200
2201   /* Use IPv4? */
2202   if (GNUNET_CONFIGURATION_have_value
2203       (plugin->env->cfg, plugin->name, "USE_IPv4"))
2204   {
2205     plugin->use_ipv4 =
2206         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
2207                                               "USE_IPv4");
2208   }
2209   else
2210     plugin->use_ipv4 = GNUNET_YES;
2211   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2212                    _("IPv4 support is %s\n"),
2213                    (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled");
2214
2215   /* Use IPv6? */
2216   if (GNUNET_CONFIGURATION_have_value
2217       (plugin->env->cfg, plugin->name, "USE_IPv6"))
2218   {
2219     plugin->use_ipv6 =
2220         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
2221                                               "USE_IPv6");
2222   }
2223   else
2224     plugin->use_ipv6 = GNUNET_YES;
2225   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2226                    _("IPv6 support is %s\n"),
2227                    (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled");
2228
2229   if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO))
2230   {
2231     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
2232                      _
2233                      ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
2234                      plugin->name);
2235     return GNUNET_SYSERR;
2236   }
2237
2238   /* Reading port number from config file */
2239   if ((GNUNET_OK !=
2240        GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
2241                                               "PORT", &port)) || (port > 65535))
2242   {
2243     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
2244                      _("Port is required! Fix in configuration\n"),
2245                      plugin->name);
2246     return GNUNET_SYSERR;
2247   }
2248   plugin->port = port;
2249
2250   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2251                    _("Using port %u\n"), plugin->port);
2252
2253   if ((plugin->use_ipv4 == GNUNET_YES) &&
2254       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2255                           plugin->name, "BINDTO", &bind4_address)))
2256   {
2257     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2258                      "Binding %s plugin to specific IPv4 address: `%s'\n",
2259                      plugin->protocol, bind4_address);
2260     plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
2261     if (1 != inet_pton (AF_INET, bind4_address,
2262                         &plugin->server_addr_v4->sin_addr))
2263     {
2264         GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
2265                          _
2266                          ("Specific IPv4 address `%s' in configuration file is invalid!\n"),
2267                          bind4_address);
2268       GNUNET_free (bind4_address);
2269       GNUNET_free (plugin->server_addr_v4);
2270       plugin->server_addr_v4 = NULL;
2271       return GNUNET_SYSERR;
2272     }
2273     else
2274     {
2275       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2276                          _("Binding to IPv4 address %s\n"), bind4_address);
2277       plugin->server_addr_v4->sin_family = AF_INET;
2278       plugin->server_addr_v4->sin_port = htons (plugin->port);
2279     }
2280     GNUNET_free (bind4_address);
2281   }
2282
2283   if ((plugin->use_ipv6 == GNUNET_YES) &&
2284       (GNUNET_YES ==
2285        GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
2286                                               "BINDTO6", &bind6_address)))
2287   {
2288     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2289                      "Binding %s plugin to specific IPv6 address: `%s'\n",
2290                      plugin->protocol, bind6_address);
2291     plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
2292     if (1 !=
2293         inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
2294     {
2295       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
2296                        _
2297                        ("Specific IPv6 address `%s' in configuration file is invalid!\n"),
2298                        bind6_address);
2299       GNUNET_free (bind6_address);
2300       GNUNET_free (plugin->server_addr_v6);
2301       plugin->server_addr_v6 = NULL;
2302       return GNUNET_SYSERR;
2303     }
2304     else
2305     {
2306       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2307                          _("Binding to IPv6 address %s\n"), bind6_address);
2308       plugin->server_addr_v6->sin6_family = AF_INET6;
2309       plugin->server_addr_v6->sin6_port = htons (plugin->port);
2310     }
2311     GNUNET_free (bind6_address);
2312   }
2313
2314   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
2315                                               "EXTERNAL_HOSTNAME", &plugin->external_hostname))
2316   {
2317       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2318                        _("Using external hostname `%s'\n"), plugin->external_hostname);
2319       plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (&server_notify_external_hostname, plugin);
2320   }
2321   else
2322     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2323                      "No external hostname configured\n");
2324
2325
2326   /* Optional parameters */
2327   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
2328                       plugin->name,
2329                       "MAX_CONNECTIONS", &max_connections))
2330     max_connections = 128;
2331   plugin->max_connections = max_connections;
2332
2333   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2334                    _("Maximum number of connections is %u\n"),
2335                    plugin->max_connections);
2336   return GNUNET_OK;
2337 }
2338
2339 /**
2340  * Session was idle, so disconnect it
2341  */
2342
2343 static void
2344 server_session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2345 {
2346   GNUNET_assert (NULL != cls);
2347   struct Session *s = cls;
2348
2349   s->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2350   GNUNET_log (TIMEOUT_LOG,
2351               "Session %p was idle for %llu ms, disconnecting\n",
2352               s, (unsigned long long) TIMEOUT.rel_value);
2353
2354   /* call session destroy function */
2355  GNUNET_assert (GNUNET_OK == server_disconnect (s));
2356 }
2357
2358 /**
2359 * Start session timeout
2360 */
2361 static void
2362 server_start_session_timeout (struct Session *s)
2363 {
2364  GNUNET_assert (NULL != s);
2365  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s->timeout_task);
2366  s->timeout_task =  GNUNET_SCHEDULER_add_delayed (TIMEOUT,
2367                                                   &server_session_timeout,
2368                                                   s);
2369  GNUNET_log (TIMEOUT_LOG,
2370              "Timeout for session %p set to %llu ms\n",
2371              s,  (unsigned long long) TIMEOUT.rel_value);
2372 }
2373
2374
2375 /**
2376 * Increment session timeout due to activity
2377 */
2378 static void
2379 server_reschedule_session_timeout (struct Session *s)
2380 {
2381  GNUNET_assert (NULL != s);
2382  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != s->timeout_task);
2383
2384  GNUNET_SCHEDULER_cancel (s->timeout_task);
2385  s->timeout_task =  GNUNET_SCHEDULER_add_delayed (TIMEOUT,
2386                                                   &server_session_timeout,
2387                                                   s);
2388  GNUNET_log (TIMEOUT_LOG,
2389              "Timeout rescheduled for session %p set to %llu ms\n",
2390              s, (unsigned long long) TIMEOUT.rel_value);
2391 }
2392
2393 /**
2394  * Exit point from the plugin.
2395  */
2396 void *
2397 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
2398 {
2399   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2400   struct HTTP_Server_Plugin *plugin = api->cls;
2401
2402   if (GNUNET_SCHEDULER_NO_TASK != plugin->notify_ext_task)
2403   {
2404       GNUNET_SCHEDULER_cancel (plugin->notify_ext_task);
2405       plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
2406   }
2407
2408   if (NULL != plugin->ext_addr)
2409   {
2410       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
2411                        "Notifying transport to remove address `%s'\n",
2412                        http_common_plugin_address_to_string (NULL,
2413                            plugin->ext_addr,
2414                            plugin->ext_addr_len));
2415       plugin->env->notify_address (plugin->env->cls,
2416                                    GNUNET_NO,
2417                                    plugin->ext_addr,
2418                                    plugin->ext_addr_len);
2419   }
2420
2421   /* Stop to report addresses to transport service */
2422   server_stop_report_addresses (plugin);
2423
2424   server_stop (plugin);
2425
2426   /* Clean up */
2427   GNUNET_free_non_null (plugin->external_hostname);
2428   GNUNET_free_non_null (plugin->ext_addr);
2429   GNUNET_free_non_null (plugin->server_addr_v4);
2430   GNUNET_free_non_null (plugin->server_addr_v6);
2431
2432   GNUNET_free (plugin);
2433   GNUNET_free (api);
2434   return NULL;
2435 }
2436
2437
2438 /**
2439  * Entry point for the plugin.
2440  */
2441 void *
2442 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2443 {
2444   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2445   struct GNUNET_TRANSPORT_PluginFunctions *api;
2446   struct HTTP_Server_Plugin *plugin;
2447
2448   plugin = GNUNET_malloc (sizeof (struct HTTP_Server_Plugin));
2449   plugin->env = env;
2450   p = plugin;
2451   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2452   api->cls = plugin;
2453   api->send = &http_server_plugin_send;
2454   api->disconnect = &http_server_plugin_disconnect;
2455   api->check_address = &http_server_plugin_address_suggested;
2456   api->get_session = &http_server_plugin_get_session;
2457
2458   api->address_to_string = &http_common_plugin_address_to_string;
2459   api->string_to_address = &http_common_plugin_string_to_address;
2460   api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2461
2462 #if BUILD_HTTPS
2463   plugin->name = "transport-https_server";
2464   plugin->protocol = "https";
2465 #else
2466   plugin->name = "transport-http_server";
2467   plugin->protocol = "http";
2468 #endif
2469
2470   /* Configure plugin */
2471   if (GNUNET_SYSERR == server_configure_plugin (plugin))
2472   {
2473       LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2474       return NULL;
2475   }
2476
2477   /* Check IPv6 support */
2478   if (GNUNET_YES == plugin->use_ipv6)
2479     plugin->use_ipv6 = server_check_ipv6_support (plugin);
2480
2481   /* Report addresses to transport service */
2482   server_start_report_addresses (plugin);
2483
2484   if (GNUNET_SYSERR == server_start (plugin))
2485   {
2486       LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2487       return NULL;
2488   }
2489
2490   return api;
2491 }
2492
2493
2494
2495
2496 /* end of plugin_transport_http_server.c */