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