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