684b7593b9753f5c2cbad4b0ac26bb9ede84c1be
[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 "microhttpd.h"
39
40 #if BUILD_HTTPS
41 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_server_init
42 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_server_done
43 #else
44 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_server_init
45 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_server_done
46 #endif
47
48
49 #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING
50
51 /**
52  * After how long do we expire an address that we
53  * learned from another peer if it is not reconfirmed
54  * by anyone?
55  */
56 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
57
58
59 /**
60  * Encapsulation of all of the state of the plugin.
61  */
62 struct Plugin;
63
64
65 /**
66  * Session handle for connections.
67  */
68 struct Session
69 {
70   /**
71    * To whom are we talking to (set to our identity
72    * if we are still waiting for the welcome message)
73    */
74   struct GNUNET_PeerIdentity sender;
75
76   /**
77    * Stored in a linked list.
78    */
79   struct Session *next;
80
81   /**
82    * Pointer to the global plugin struct.
83    */
84   struct HTTP_Server_Plugin *plugin;
85
86   /**
87    * The client (used to identify this connection)
88    */
89   /* void *client; */
90
91   /**
92    * Continuation function to call once the transmission buffer
93    * has again space available.  NULL if there is no
94    * continuation to call.
95    */
96   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
97
98   /**
99    * Closure for transmit_cont.
100    */
101   void *transmit_cont_cls;
102
103   /**
104    * At what time did we reset last_received last?
105    */
106   struct GNUNET_TIME_Absolute last_quota_update;
107
108   /**
109    * How many bytes have we received since the "last_quota_update"
110    * timestamp?
111    */
112   uint64_t last_received;
113
114   /**
115    * Number of bytes per ms that this peer is allowed
116    * to send to us.
117    */
118   uint32_t quota;
119
120 };
121
122 /**
123  * Encapsulation of all of the state of the plugin.
124  */
125 struct HTTP_Server_Plugin
126 {
127   /**
128    * Our environment.
129    */
130   struct GNUNET_TRANSPORT_PluginEnvironment *env;
131
132   /**
133    * List of open sessions.
134    */
135   struct Session *sessions;
136
137   char *name;
138   char *protocol;
139   char *external_hostname;
140
141   /**
142    * Maximum number of sockets the plugin can use
143    * Each http inbound /outbound connections are two connections
144    */
145   unsigned int max_connections;
146
147   /**
148    * External hostname the plugin can be connected to, can be different to
149    * the host's FQDN, used e.g. for reverse proxying
150    */
151   struct HttpAddress *ext_addr;
152
153   /**
154    * External address length
155    */
156   size_t ext_addr_len;
157
158   /**
159    * use IPv6
160    */
161   uint16_t use_ipv6;
162
163   /**
164    * use IPv4
165    */
166   uint16_t use_ipv4;
167
168   /**
169    * Port used
170    */
171   uint16_t port;
172
173   /**
174    * Task calling transport service about external address
175    */
176   GNUNET_SCHEDULER_TaskIdentifier notify_ext_task;
177
178   /**
179    * NAT handle & address management
180    */
181   struct GNUNET_NAT_Handle *nat;
182
183   /**
184    * List of own addresses
185    */
186
187   /**
188    * IPv4 addresses DLL head
189    */
190   struct HttpAddressWrapper *addr_head;
191
192   /**
193    * IPv4 addresses DLL tail
194    */
195   struct HttpAddressWrapper *addr_tail;
196
197   /**
198    * IPv4 server socket to bind to
199    */
200   struct sockaddr_in *server_addr_v4;
201
202   /**
203    * IPv6 server socket to bind to
204    */
205   struct sockaddr_in6 *server_addr_v6;
206
207
208   /**
209    * MHD IPv4 daemon
210    */
211   struct MHD_Daemon *server_v4;
212
213   /**
214    * MHD IPv4 daemon
215    */
216   struct MHD_Daemon *server_v6;
217 };
218
219 GNUNET_NETWORK_STRUCT_BEGIN
220
221 /**
222  * HTTP addresses including a full URI
223  */
224 struct HttpAddress
225 {
226   /**
227    * Length of the address following in NBO
228    */
229   uint32_t addr_len GNUNET_PACKED;
230
231   /**
232    * Address following
233    */
234   void *addr GNUNET_PACKED;
235 };
236 GNUNET_NETWORK_STRUCT_END
237
238 /**
239  * Wrapper to manage addresses
240  */
241 struct HttpAddressWrapper
242 {
243   /**
244    * Linked list next
245    */
246   struct HttpAddressWrapper *next;
247
248   /**
249    * Linked list previous
250    */
251   struct HttpAddressWrapper *prev;
252
253   struct HttpAddress *addr;
254 };
255
256
257 /**
258  * Function that can be used by the transport service to transmit
259  * a message using the plugin.   Note that in the case of a
260  * peer disconnecting, the continuation MUST be called
261  * prior to the disconnect notification itself.  This function
262  * will be called with this peer's HELLO message to initiate
263  * a fresh connection to another peer.
264  *
265  * @param cls closure
266  * @param session which session must be used
267  * @param msgbuf the message to transmit
268  * @param msgbuf_size number of bytes in 'msgbuf'
269  * @param priority how important is the message (most plugins will
270  *                 ignore message priority and just FIFO)
271  * @param to how long to wait at most for the transmission (does not
272  *                require plugins to discard the message after the timeout,
273  *                just advisory for the desired delay; most plugins will ignore
274  *                this as well)
275  * @param cont continuation to call once the message has
276  *        been transmitted (or if the transport is ready
277  *        for the next transmission call; or if the
278  *        peer disconnected...); can be NULL
279  * @param cont_cls closure for cont
280  * @return number of bytes used (on the physical network, with overheads);
281  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
282  *         and does NOT mean that the message was not transmitted (DV)
283  */
284 static ssize_t
285 http_server_plugin_send (void *cls,
286                   struct Session *session,
287                   const char *msgbuf, size_t msgbuf_size,
288                   unsigned int priority,
289                   struct GNUNET_TIME_Relative to,
290                   GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
291 {
292   struct HTTP_Server_Plugin *plugin = cls;
293   int bytes_sent = 0;
294
295   GNUNET_assert (plugin != NULL);
296   GNUNET_assert (session != NULL);
297
298   /*  struct Plugin *plugin = cls; */
299   return bytes_sent;
300 }
301
302
303
304 /**
305  * Function that can be used to force the plugin to disconnect
306  * from the given peer and cancel all previous transmissions
307  * (and their continuationc).
308  *
309  * @param cls closure
310  * @param target peer from which to disconnect
311  */
312 static void
313 http_server_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
314 {
315   // struct Plugin *plugin = cls;
316   // FIXME
317 }
318
319
320 /**
321  * Convert the transports address to a nice, human-readable
322  * format.
323  *
324  * @param cls closure
325  * @param type name of the transport that generated the address
326  * @param addr one of the addresses of the host, NULL for the last address
327  *        the specific address format depends on the transport
328  * @param addrlen length of the address
329  * @param numeric should (IP) addresses be displayed in numeric form?
330  * @param timeout after how long should we give up?
331  * @param asc function to call on each string
332  * @param asc_cls closure for asc
333  */
334 static void
335 http_server_plugin_address_pretty_printer (void *cls, const char *type,
336                                         const void *addr, size_t addrlen,
337                                         int numeric,
338                                         struct GNUNET_TIME_Relative timeout,
339                                         GNUNET_TRANSPORT_AddressStringCallback
340                                         asc, void *asc_cls)
341 {
342   asc (asc_cls, NULL);
343 }
344
345
346
347 /**
348  * Another peer has suggested an address for this
349  * peer and transport plugin.  Check that this could be a valid
350  * address.  If so, consider adding it to the list
351  * of addresses.
352  *
353  * @param cls closure
354  * @param addr pointer to the address
355  * @param addrlen length of addr
356  * @return GNUNET_OK if this is a plausible address for this peer
357  *         and transport
358  */
359 static int
360 http_server_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
361 {
362   /* struct Plugin *plugin = cls; */
363
364   /* check if the address is plausible; if so,
365    * add it to our list! */
366   return GNUNET_OK;
367 }
368
369
370 /**
371  * Function called for a quick conversion of the binary address to
372  * a numeric address.  Note that the caller must not free the
373  * address and that the next call to this function is allowed
374  * to override the address again.
375  *
376  * @param cls closure
377  * @param addr binary address
378  * @param addrlen length of the address
379  * @return string representing the same address
380  */
381 static const char *
382 http_server_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
383 {
384   GNUNET_break (0);
385   return NULL;
386 }
387
388
389 static void *
390 server_find_address (struct HTTP_Server_Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen)
391 {
392   struct HttpAddressWrapper *w = NULL;
393   char *saddr;
394
395   GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen));
396   w = plugin->addr_head;
397   while (NULL != w)
398   {
399       if (0 == strcmp (saddr, w->addr->addr))
400         break;
401       w = w->next;
402   }
403
404   GNUNET_free (saddr);
405   return w;
406 }
407
408 static void
409 server_add_address (void *cls, int add_remove, const struct sockaddr *addr,
410                  socklen_t addrlen)
411 {
412   struct HTTP_Server_Plugin *plugin = cls;
413   struct HttpAddressWrapper *w = NULL;
414   char *saddr;
415   size_t haddrlen;
416
417   GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen));
418
419   haddrlen = sizeof (struct HttpAddress) + strlen(saddr) + 1;
420   w = GNUNET_malloc (sizeof (struct HttpAddressWrapper));
421   w->addr = GNUNET_malloc (haddrlen);
422   w->addr->addr = &w->addr[1];
423   w->addr->addr_len = htonl (strlen(saddr) + 1);
424   memcpy (w->addr->addr, saddr, strlen(saddr) + 1);
425   GNUNET_free (saddr);
426
427   GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w);
428   GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
429                    "Notifying transport to add address `%s'\n", w->addr->addr);
430
431   plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, haddrlen);
432 }
433
434
435 static void
436 server_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
437                     socklen_t addrlen)
438 {
439   struct HTTP_Server_Plugin *plugin = cls;
440   struct HttpAddressWrapper *w = NULL;
441   size_t haddrlen;
442
443   w = server_find_address (plugin, addr, addrlen);
444   if (NULL == w)
445     return;
446
447   haddrlen = sizeof (struct HttpAddress) + ntohl (w->addr->addr_len);
448   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
449                    "Notifying transport to remove address `%s'\n", http_server_plugin_address_to_string (NULL, w->addr, haddrlen));
450
451
452   GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
453   plugin->env->notify_address (plugin->env->cls, add_remove, w->addr,
454        sizeof (struct HttpAddress) + ntohl (w->addr->addr_len));
455   GNUNET_free (w->addr);
456   GNUNET_free (w);
457 }
458
459
460
461 /**
462  * Our external IP address/port mapping has changed.
463  *
464  * @param cls closure, the 'struct LocalAddrList'
465  * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
466  *     the previous (now invalid) one
467  * @param addr either the previous or the new public IP address
468  * @param addrlen actual lenght of the address
469  */
470 static void
471 server_nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
472                        socklen_t addrlen)
473 {
474   GNUNET_assert (cls != NULL);
475   struct HTTP_Server_Plugin *plugin = cls;
476
477   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
478                    "NPMC called %s to address `%s'\n",
479                    (add_remove == GNUNET_NO) ? "remove" : "add",
480                    GNUNET_a2s (addr, addrlen));
481
482   switch (add_remove)
483   {
484   case GNUNET_YES:
485     server_add_address (cls, add_remove, addr, addrlen);
486     break;
487   case GNUNET_NO:
488     server_remove_address (cls, add_remove, addr, addrlen);
489     break;
490   }
491 }
492
493
494 static int
495 server_get_addresses (struct HTTP_Server_Plugin *plugin,
496                       const char *serviceName,
497                       const struct GNUNET_CONFIGURATION_Handle *cfg,
498                       struct sockaddr ***addrs, socklen_t ** addr_lens)
499 {
500   int disablev6;
501   unsigned long long port;
502   struct addrinfo hints;
503   struct addrinfo *res;
504   struct addrinfo *pos;
505   struct addrinfo *next;
506   unsigned int i;
507   int resi;
508   int ret;
509   struct sockaddr **saddrs;
510   socklen_t *saddrlens;
511   char *hostname;
512
513   *addrs = NULL;
514   *addr_lens = NULL;
515
516   disablev6 = !plugin->use_ipv6;
517
518   port = 0;
519   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
520   {
521     GNUNET_break (GNUNET_OK ==
522                   GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
523                                                          "PORT", &port));
524     if (port > 65535)
525     {
526       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
527                   _
528                   ("Require valid port number for service in configuration!\n"));
529       return GNUNET_SYSERR;
530     }
531   }
532   if (0 == port)
533   {
534     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, plugin->name,
535                      "Starting in listen only mode\n");
536     return -1; /* listen only */
537   }
538
539
540   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
541   {
542     GNUNET_break (GNUNET_OK ==
543                   GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
544                                                          "BINDTO", &hostname));
545   }
546   else
547     hostname = NULL;
548
549   if (hostname != NULL)
550   {
551     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
552                      "Resolving `%s' since that is where `%s' will bind to.\n",
553                      hostname, serviceName);
554     memset (&hints, 0, sizeof (struct addrinfo));
555     if (disablev6)
556       hints.ai_family = AF_INET;
557     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
558         (res == NULL))
559     {
560       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
561                   hostname, gai_strerror (ret));
562       GNUNET_free (hostname);
563       return GNUNET_SYSERR;
564     }
565     next = res;
566     i = 0;
567     while (NULL != (pos = next))
568     {
569       next = pos->ai_next;
570       if ((disablev6) && (pos->ai_family == AF_INET6))
571         continue;
572       i++;
573     }
574     if (0 == i)
575     {
576       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
577                   _("Failed to find %saddress for `%s'.\n"),
578                   disablev6 ? "IPv4 " : "", hostname);
579       freeaddrinfo (res);
580       GNUNET_free (hostname);
581       return GNUNET_SYSERR;
582     }
583     resi = i;
584     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
585     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
586     i = 0;
587     next = res;
588     while (NULL != (pos = next))
589     {
590       next = pos->ai_next;
591       if ((disablev6) && (pos->ai_family == AF_INET6))
592         continue;
593       if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
594         continue;               /* not TCP */
595       if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
596         continue;               /* huh? */
597       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
598                        "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr,
599                                                                   pos->ai_addrlen));
600       if (pos->ai_family == AF_INET)
601       {
602         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
603         saddrlens[i] = pos->ai_addrlen;
604         saddrs[i] = GNUNET_malloc (saddrlens[i]);
605         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
606         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
607       }
608       else
609       {
610         GNUNET_assert (pos->ai_family == AF_INET6);
611         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
612         saddrlens[i] = pos->ai_addrlen;
613         saddrs[i] = GNUNET_malloc (saddrlens[i]);
614         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
615         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
616       }
617       i++;
618     }
619     GNUNET_free (hostname);
620     freeaddrinfo (res);
621     resi = i;
622   }
623   else
624   {
625     /* will bind against everything, just set port */
626     if (disablev6)
627     {
628       /* V4-only */
629       resi = 1;
630       i = 0;
631       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
632       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
633
634       saddrlens[i] = sizeof (struct sockaddr_in);
635       saddrs[i] = GNUNET_malloc (saddrlens[i]);
636 #if HAVE_SOCKADDR_IN_SIN_LEN
637       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
638 #endif
639       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
640       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
641     }
642     else
643     {
644       /* dual stack */
645       resi = 2;
646       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
647       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
648       i = 0;
649       saddrlens[i] = sizeof (struct sockaddr_in6);
650       saddrs[i] = GNUNET_malloc (saddrlens[i]);
651 #if HAVE_SOCKADDR_IN_SIN_LEN
652       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
653 #endif
654       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
655       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
656       i++;
657       saddrlens[i] = sizeof (struct sockaddr_in);
658       saddrs[i] = GNUNET_malloc (saddrlens[i]);
659 #if HAVE_SOCKADDR_IN_SIN_LEN
660       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
661 #endif
662       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
663       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
664     }
665   }
666   *addrs = saddrs;
667   *addr_lens = saddrlens;
668   return resi;
669 }
670
671 static void
672 server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
673 {
674   int res = GNUNET_OK;
675   struct sockaddr **addrs;
676   socklen_t *addrlens;
677
678   res = server_get_addresses (plugin,
679                               plugin->name, plugin->env->cfg,
680                               &addrs, &addrlens);
681   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
682                    _("Found %u addresses to report to NAT service\n"), res);
683
684   if (GNUNET_SYSERR == res)
685   {
686     plugin->nat = NULL;
687     return;
688   }
689
690   plugin->nat =
691       GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
692                            (unsigned int) res,
693                            (const struct sockaddr **) addrs, addrlens,
694                            &server_nat_port_map_callback, NULL, plugin);
695   while (res > 0)
696   {
697     res--;
698     GNUNET_assert (addrs[res] != NULL);
699     GNUNET_free (addrs[res]);
700   }
701   GNUNET_free_non_null (addrs);
702   GNUNET_free_non_null (addrlens);
703 }
704
705
706 static void
707 server_stop_report_addresses (struct HTTP_Server_Plugin *plugin)
708 {
709   /* Stop NAT handle */
710   if (NULL != plugin->nat)
711     GNUNET_NAT_unregister (plugin->nat);
712
713   /* Clean up addresses */
714   struct HttpAddressWrapper *w;
715
716   while (plugin->addr_head != NULL)
717   {
718     w = plugin->addr_head;
719     GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w);
720     GNUNET_free (w->addr);
721     GNUNET_free (w);
722   }
723 }
724
725
726 /**
727  * Check if IPv6 supported on this system
728  */
729 static int
730 server_check_ipv6_support (struct HTTP_Server_Plugin *plugin)
731 {
732   struct GNUNET_NETWORK_Handle *desc = NULL;
733   int res = GNUNET_NO;
734
735   /* Probe IPv6 support */
736   desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
737   if (NULL == desc)
738   {
739     if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
740         (errno == EACCES))
741     {
742       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
743     }
744     GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
745                      _
746                      ("Disabling IPv6 since it is not supported on this system!\n"));
747     res = GNUNET_NO;
748   }
749   else
750   {
751     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
752     desc = NULL;
753     res = GNUNET_YES;
754   }
755   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
756                    "Testing IPv6 on this system: %s\n",
757                    (res == GNUNET_YES) ? "successful" : "failed");
758   return res;
759 }
760
761
762 /**
763  * Function called when the service shuts down.  Unloads our plugins
764  * and cancels pending validations.
765  *
766  * @param cls closure, unused
767  * @param tc task context (unused)
768  */
769 static void
770 server_notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
771 {
772   struct HTTP_Server_Plugin *plugin = cls;
773   struct HttpAddress *eaddr;
774   char *addr;
775   size_t eaddr_len;
776   size_t uri_len;
777
778   plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
779
780   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
781     return;
782
783   GNUNET_asprintf(&addr, "%s://%s", plugin->protocol, plugin->external_hostname);
784   uri_len = strlen (addr) + 1;
785   eaddr_len = sizeof (struct HttpAddress) + uri_len;
786   eaddr = GNUNET_malloc (eaddr_len);
787   eaddr->addr_len = htonl (uri_len);
788   eaddr->addr = (void *) &eaddr[1];
789   memcpy (&eaddr->addr, addr, uri_len);
790   GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
791                    "Notifying transport about external hostname address `%s'\n", addr);
792
793   GNUNET_free (addr);
794   plugin->env->notify_address (plugin->env->cls, GNUNET_YES, eaddr, eaddr_len);
795   plugin->ext_addr = eaddr;
796   plugin->ext_addr_len = eaddr_len;
797 }
798
799
800 static int
801 server_configure_plugin (struct HTTP_Server_Plugin *plugin)
802 {
803   unsigned long long port;
804   unsigned long long max_connections;
805   char *bind4_address = NULL;
806   char *bind6_address = NULL;
807
808   /* Use IPv4? */
809   if (GNUNET_CONFIGURATION_have_value
810       (plugin->env->cfg, plugin->name, "USE_IPv4"))
811   {
812     plugin->use_ipv4 =
813         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
814                                               "USE_IPv4");
815   }
816   else
817     plugin->use_ipv4 = GNUNET_YES;
818   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
819                    _("IPv4 support is %s\n"),
820                    (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled");
821
822   /* Use IPv6? */
823   if (GNUNET_CONFIGURATION_have_value
824       (plugin->env->cfg, plugin->name, "USE_IPv6"))
825   {
826     plugin->use_ipv6 =
827         GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
828                                               "USE_IPv6");
829   }
830   else
831     plugin->use_ipv6 = GNUNET_YES;
832   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
833                    _("IPv6 support is %s\n"),
834                    (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled");
835
836   if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO))
837   {
838     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
839                      _
840                      ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
841                      plugin->name);
842     return GNUNET_SYSERR;
843   }
844
845   /* Reading port number from config file */
846   if ((GNUNET_OK !=
847        GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
848                                               "PORT", &port)) || (port > 65535))
849   {
850     GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
851                      _("Port is required! Fix in configuration\n"),
852                      plugin->name);
853     return GNUNET_SYSERR;
854   }
855   plugin->port = port;
856
857   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
858                    _("Using port %u\n"), plugin->port);
859
860   if ((plugin->use_ipv4 == GNUNET_YES) &&
861       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
862                           plugin->name, "BINDTO", &bind4_address)))
863   {
864     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
865                      "Binding %s plugin to specific IPv4 address: `%s'\n",
866                      plugin->protocol, bind4_address);
867     plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
868     if (1 != inet_pton (AF_INET, bind4_address,
869                         &plugin->server_addr_v4->sin_addr))
870     {
871         GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
872                          _
873                          ("Specific IPv4 address `%s' in configuration file is invalid!\n"),
874                          bind4_address);
875       GNUNET_free (bind4_address);
876       GNUNET_free (plugin->server_addr_v4);
877       plugin->server_addr_v4 = NULL;
878       return GNUNET_SYSERR;
879     }
880     else
881     {
882       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
883                          _("Binding to IPv4 address %s\n"), bind4_address);
884       plugin->server_addr_v4->sin_family = AF_INET;
885       plugin->server_addr_v4->sin_port = htons (plugin->port);
886     }
887     GNUNET_free (bind4_address);
888   }
889
890   if ((plugin->use_ipv6 == GNUNET_YES) &&
891       (GNUNET_YES ==
892        GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
893                                               "BINDTO6", &bind6_address)))
894   {
895     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
896                      "Binding %s plugin to specific IPv6 address: `%s'\n",
897                      plugin->protocol, bind6_address);
898     plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
899     if (1 !=
900         inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
901     {
902       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
903                        _
904                        ("Specific IPv6 address `%s' in configuration file is invalid!\n"),
905                        bind6_address);
906       GNUNET_free (bind6_address);
907       GNUNET_free (plugin->server_addr_v6);
908       plugin->server_addr_v6 = NULL;
909       return GNUNET_SYSERR;
910     }
911     else
912     {
913       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
914                          _("Binding to IPv6 address %s\n"), bind6_address);
915       plugin->server_addr_v6->sin6_family = AF_INET6;
916       plugin->server_addr_v6->sin6_port = htons (plugin->port);
917     }
918     GNUNET_free (bind6_address);
919   }
920
921   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
922                                               "EXTERNAL_HOSTNAME", &plugin->external_hostname))
923   {
924       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
925                        _("Using external hostname `%s'\n"), plugin->external_hostname);
926       plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (&server_notify_external_hostname, plugin);
927   }
928   else
929     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
930                      "No external hostname configured\n");
931
932
933   /* Optional parameters */
934   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
935                       plugin->name,
936                       "MAX_CONNECTIONS", &max_connections))
937     max_connections = 128;
938   plugin->max_connections = max_connections;
939
940   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
941                    _("Maximum number of connections is %u\n"),
942                    plugin->max_connections);
943 GNUNET_break(0);
944   return GNUNET_OK;
945 }
946
947
948 /**
949  * Exit point from the plugin.
950  */
951 void *
952 LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
953 {
954   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
955   struct HTTP_Server_Plugin *plugin = api->cls;
956
957   if (GNUNET_SCHEDULER_NO_TASK != plugin->notify_ext_task)
958   {
959       GNUNET_SCHEDULER_cancel (plugin->notify_ext_task);
960       plugin->notify_ext_task = GNUNET_SCHEDULER_NO_TASK;
961   }
962
963   if (NULL != plugin->ext_addr)
964   {
965       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
966                        "Notifying transport to remove address `%s'\n",
967                        http_server_plugin_address_to_string (NULL,
968                            plugin->ext_addr,
969                            plugin->ext_addr_len));
970       plugin->env->notify_address (plugin->env->cls,
971                                    GNUNET_NO,
972                                    plugin->ext_addr,
973                                    plugin->ext_addr_len);
974   }
975
976   /* Stop to report addresses to transport service */
977   server_stop_report_addresses (plugin);
978
979   /* Clean up */
980   GNUNET_free_non_null (plugin->external_hostname);
981   GNUNET_free_non_null (plugin->ext_addr);
982   GNUNET_free_non_null (plugin->server_addr_v4);
983   GNUNET_free_non_null (plugin->server_addr_v6);
984
985
986   GNUNET_free (plugin);
987   GNUNET_free (api);
988   return NULL;
989 }
990
991
992 /**
993  * Entry point for the plugin.
994  */
995 void *
996 LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
997 {
998   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
999   struct GNUNET_TRANSPORT_PluginFunctions *api;
1000   struct HTTP_Server_Plugin *plugin;
1001
1002   plugin = GNUNET_malloc (sizeof (struct HTTP_Server_Plugin));
1003   plugin->env = env;
1004   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1005   api->cls = plugin;
1006   api->send = &http_server_plugin_send;
1007   api->disconnect = &http_server_plugin_disconnect;
1008   api->address_pretty_printer = &http_server_plugin_address_pretty_printer;
1009   api->check_address = &http_server_plugin_address_suggested;
1010   api->address_to_string = &http_server_plugin_address_to_string;
1011
1012 #if BUILD_HTTPS
1013   plugin->name = "transport-https_server";
1014   plugin->protocol = "https";
1015 #else
1016   plugin->name = "transport-http_server";
1017   plugin->protocol = "http";
1018 #endif
1019
1020   /* Configure plugin */
1021   if (GNUNET_SYSERR == server_configure_plugin (plugin))
1022   {
1023       LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
1024       return NULL;
1025   }
1026
1027   /* Check IPv6 support */
1028   if (GNUNET_YES == plugin->use_ipv6)
1029     plugin->use_ipv6 = server_check_ipv6_support (plugin);
1030
1031   /* Report addresses to transport service */
1032   server_start_report_addresses (plugin);
1033
1034   return api;
1035 }
1036
1037
1038
1039
1040 /* end of plugin_transport_http_server.c */