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