bfd9ae7294a5c9c9b16bcf1a1296916769fc58ed
[oweals/gnunet.git] / src / hostlist / hostlist-server.c
1 /*
2      This file is part of GNUnet.
3      (C) 2008, 2009, 2010 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 2, 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 hostlist/hostlist-server.c
23  * @author Christian Grothoff
24  * @brief application to provide an integrated hostlist HTTP server
25  */
26
27 #include "platform.h"
28 #include <microhttpd.h>
29 #include "hostlist-server.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet-daemon-hostlist.h"
33 #include "gnunet_resolver_service.h"
34
35 #define DEBUG_HOSTLIST_SERVER GNUNET_NO
36
37 /**
38  * How often should we recalculate our response to hostlist requests?
39  */
40 #define RESPONSE_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
41
42 /**
43  * Handle to the HTTP server as provided by libmicrohttpd for IPv6.
44  */
45 static struct MHD_Daemon *daemon_handle_v6;
46
47 /**
48  * Handle to the HTTP server as provided by libmicrohttpd for IPv4.
49  */
50 static struct MHD_Daemon *daemon_handle_v4;
51
52 /**
53  * Our configuration.
54  */
55 static const struct GNUNET_CONFIGURATION_Handle *cfg;
56
57 /**
58  * Our scheduler.
59  */
60 static struct GNUNET_SCHEDULER_Handle *sched;
61
62 /**
63  * For keeping statistics.
64  */ 
65 static struct GNUNET_STATISTICS_Handle *stats;
66
67 /**
68  * Handle to the core service (NULL until we've connected to it).
69  */
70 struct GNUNET_CORE_Handle *core;
71
72 /**
73  * Our primary task for IPv4.
74  */
75 static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4;
76
77 /**
78  * Our primary task for IPv6.
79  */
80 static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6;
81
82 /**
83  * Task that updates our HTTP response.
84  */
85 static GNUNET_SCHEDULER_TaskIdentifier response_task;
86
87 /**
88  * Our canonical response.
89  */
90 static struct MHD_Response *response;
91
92 /**
93  * NULL if we are not currenlty iterating over peer information.
94  */
95 static struct GNUNET_PEERINFO_IteratorContext *pitr;
96
97 /**
98  * Context for host processor.
99  */
100 struct HostSet
101 {
102   unsigned int size;
103
104   char *data;
105 };
106
107 /**
108  * Set if we are allowed to advertise our hostlist to others.
109  */
110 static int advertising;
111
112 /**
113  * Task that will produce a new response object.
114  */
115 static void
116 update_response (void *cls,
117                  const struct GNUNET_SCHEDULER_TaskContext *tc);
118
119 /**
120  * Function that assembles our response.
121  */
122 static void
123 finish_response (struct HostSet *results)
124 {
125   struct GNUNET_TIME_Relative freq;
126
127   if (response != NULL)
128     MHD_destroy_response (response);
129 #if DEBUG_HOSTLIST_SERVER
130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131               "Creating hostlist response with %u bytes\n",
132               (unsigned int) results->size);
133 #endif
134   response = MHD_create_response_from_data (results->size,
135                                             results->data, MHD_YES, MHD_NO);
136   if ( (daemon_handle_v4 != NULL) ||
137        (daemon_handle_v6 != NULL) )
138     {
139       freq = RESPONSE_UPDATE_FREQUENCY;
140       if (results->size == 0)
141         freq = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250);
142       /* schedule next update of the response */
143       response_task = GNUNET_SCHEDULER_add_delayed (sched,
144                                                     freq,
145                                                     &update_response,
146                                                     NULL);
147     }
148   else
149     {
150       /* already past shutdown */
151       MHD_destroy_response (response);
152       response = NULL;
153     }
154   GNUNET_STATISTICS_set (stats,
155                          gettext_noop("bytes in hostlist"),
156                          results->size,
157                          GNUNET_YES);
158   GNUNET_free (results);
159 }
160
161
162 /**
163  * Set 'cls' to GNUNET_YES (we have an address!).
164  *
165  * @param cls closure, an 'int*'
166  * @param tname name of the transport (ignored)
167  * @param expiration expiration time (call is ignored if this is in the past)
168  * @param addr the address (ignored)
169  * @param addrlen length of the address (ignored)
170  * @return  GNUNET_SYSERR to stop iterating (unless expiration has occured)
171  */
172 static int
173 check_has_addr (void *cls,
174                 const char *tname,
175                 struct GNUNET_TIME_Absolute expiration,
176                 const void *addr, size_t addrlen)
177 {
178   int *arg = cls;
179
180   if (GNUNET_TIME_absolute_get_remaining (expiration).value == 0)
181     {
182       GNUNET_STATISTICS_update (stats,
183                                 gettext_noop("expired addresses encountered"),
184                                 1,
185                                 GNUNET_YES);
186       return GNUNET_YES; /* ignore this address */
187     }
188   *arg = GNUNET_YES;
189   return GNUNET_SYSERR;
190 }
191
192
193 /**
194  * Callback that processes each of the known HELLOs for the
195  * hostlist response construction.
196  */
197 static void
198 host_processor (void *cls,
199                 const struct GNUNET_PeerIdentity * peer,
200                 const struct GNUNET_HELLO_Message *hello,
201                 uint32_t trust)
202 {
203   struct HostSet *results = cls;
204   size_t old;
205   size_t s;
206   int has_addr;
207   
208   if (peer == NULL)
209     {
210       pitr = NULL;
211       finish_response (results);
212       return;
213     }
214   if (hello == NULL)
215     return;
216   has_addr = GNUNET_NO;
217   GNUNET_HELLO_iterate_addresses (hello,
218                                   GNUNET_NO,
219                                   &check_has_addr,
220                                   &has_addr);
221   if (GNUNET_NO == has_addr)
222     {
223       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224                   "HELLO for peer `%4s' has no address, not suitable for hostlist!\n",
225                   GNUNET_i2s (peer));
226       GNUNET_STATISTICS_update (stats,
227                                 gettext_noop("HELLOs without addresses encountered (ignored)"),
228                                 1,
229                                 GNUNET_NO);
230       return; 
231     }
232   old = results->size;
233   s = GNUNET_HELLO_size(hello);
234 #if DEBUG_HOSTLIST_SERVER
235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236               "Received %u bytes of `%s' from peer `%s' for hostlist.\n",
237               (unsigned int) s,
238               "HELLO",
239               GNUNET_i2s (peer));
240 #endif
241   if (old + s >= GNUNET_MAX_MALLOC_CHECKED)
242     {
243       GNUNET_STATISTICS_update (stats,
244                                 gettext_noop("bytes not included in hostlist (size limit)"),
245                                 s,
246                                 GNUNET_NO);
247       return; /* too large, skip! */
248     }
249   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
250               "Adding peer `%s' to hostlist (%u bytes)\n",
251               GNUNET_i2s (peer),
252               (unsigned int) s);
253   GNUNET_array_grow (results->data,
254                      results->size,
255                      old + s);
256   memcpy (&results->data[old], hello, s);
257 }
258
259
260 /**
261  * Task that will produce a new response object.
262  */
263 static void
264 update_response (void *cls,
265                  const struct GNUNET_SCHEDULER_TaskContext *tc)
266 {
267   struct HostSet *results;
268
269   response_task = GNUNET_SCHEDULER_NO_TASK;
270   results = GNUNET_malloc(sizeof(struct HostSet));
271   pitr = GNUNET_PEERINFO_iterate (cfg, sched, 
272                                   NULL,
273                                   0, 
274                                   GNUNET_TIME_UNIT_MINUTES,
275                                   &host_processor,
276                                   results);
277 }
278
279
280 /**
281  * Hostlist access policy (very permissive, allows everything).
282  */
283 static int
284 accept_policy_callback (void *cls,
285                         const struct sockaddr *addr, socklen_t addrlen)
286 {
287   if (NULL == response)
288     {
289 #if DEBUG_HOSTLIST_SERVER
290       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291                   "Received request for hostlist, but I am not yet ready; rejecting!\n");
292 #endif
293       return MHD_NO;
294     }
295   return MHD_YES;               /* accept all */
296 }
297
298
299 /**
300  * Main request handler.
301  */
302 static int
303 access_handler_callback (void *cls,
304                          struct MHD_Connection *connection,
305                          const char *url,
306                          const char *method,
307                          const char *version,
308                          const char *upload_data,
309                          size_t*upload_data_size, void **con_cls)
310 {
311   static int dummy;
312   
313   if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
314     {
315       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
316                   _("Refusing `%s' request to hostlist server\n"),
317                   method);
318       GNUNET_STATISTICS_update (stats,
319                                 gettext_noop("hostlist requests refused (not HTTP GET)"),
320                                 1,
321                                 GNUNET_YES);
322       return MHD_NO;
323     }
324   if (NULL == *con_cls)
325     {
326       (*con_cls) = &dummy;
327 #if DEBUG_HOSTLIST_SERVER
328       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329                   _("Sending 100 CONTINUE reply\n"));
330 #endif
331       return MHD_YES;           /* send 100 continue */
332     }
333   if (*upload_data_size != 0)
334     {
335       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
336                   _("Refusing `%s' request with %llu bytes of upload data\n"),
337                   method,
338                   (unsigned long long) *upload_data_size);
339       GNUNET_STATISTICS_update (stats,
340                                 gettext_noop("hostlist requests refused (upload data)"),
341                                 1,
342                                 GNUNET_YES);
343       return MHD_NO;              /* do not support upload data */
344     }
345   if (response == NULL)
346     {
347       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
348                   _("Could not handle hostlist request since I do not have a response yet\n"));
349       GNUNET_STATISTICS_update (stats,
350                                 gettext_noop("hostlist requests refused (not ready)"),
351                                 1,
352                                 GNUNET_YES);
353       return MHD_NO;              /* internal error, no response yet */
354     }
355   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
356               _("Received request for our hostlist\n"));
357   GNUNET_STATISTICS_update (stats,
358                             gettext_noop("hostlist requests processed"),
359                             1,
360                             GNUNET_YES);
361   return MHD_queue_response (connection, MHD_HTTP_OK, response);
362 }
363
364 /*
365  * Buffer for the hostlist address
366  */
367 char hostlist_uri[255];
368
369 /**
370  * Handler called by core when core is ready to transmit message
371  * @param cls   closure
372  * @param size  size of buffer to copy message to
373  * @param buf   buffer to copy message to
374  */
375 static size_t
376 adv_transmit_ready ( void *cls, size_t size, void *buf)
377 {
378   size_t transmission_size;
379   size_t uri_size; /* Including \0 termination! */
380   uri_size = strlen ( hostlist_uri ) + 1;
381
382   struct GNUNET_HOSTLIST_ADV_Message * adv_message;
383   adv_message = GNUNET_malloc ( sizeof(struct GNUNET_HOSTLIST_ADV_Message) + uri_size);
384   if ( NULL == adv_message)
385    {
386    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
387        "Could not allocate memory for the message");
388    return GNUNET_NO;
389    }
390   transmission_size = sizeof (struct GNUNET_HOSTLIST_ADV_Message) + uri_size;
391
392   adv_message->header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
393   adv_message->header.size = htons (transmission_size);
394   memcpy(&adv_message[1],hostlist_uri,uri_size);
395
396   if (buf == NULL)
397     {
398       GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG, "Transmission failed, buffer invalid!\n" );
399       return 0;
400     }
401
402   if ( size >= transmission_size )
403     {
404       memcpy ( buf, adv_message, transmission_size );
405       GNUNET_log ( GNUNET_ERROR_TYPE_DEBUG, "Sent advertisement message: Copied %d bytes into buffer!\n", transmission_size);
406       GNUNET_free ( adv_message );
407       return transmission_size;
408     }
409
410   GNUNET_free (adv_message  );
411   return size;
412 }
413
414 /**
415  * Method that asks core service to transmit the message to the peer
416  * @param peer peer to transmit message to
417  * @param size size of the message
418  */
419 static size_t
420 adv_transmit_message ( const struct GNUNET_PeerIdentity * peer, size_t size )
421 {
422   /* transmit message to peer */
423   if ( NULL == core)
424     {
425       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
426                   _("Not connected to core, unable to send advertisement message\n"));
427       return GNUNET_NO;
428     }
429
430   struct GNUNET_TIME_Relative timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, GNUNET_ADV_TIMEOUT);
431   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432               _("Asked core to transmit advertisement message with a size of %u bytes\n"), size);
433   struct GNUNET_CORE_TransmitHandle * th;
434   th = GNUNET_CORE_notify_transmit_ready (core,
435                                      0,
436                                      timeout,
437                                      peer,
438                                      size,
439                                      &adv_transmit_ready, NULL);
440   if ( NULL == th )
441     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
442                 _("Advertisement message could not be queued by core\n"));
443     return GNUNET_NO;
444
445   return GNUNET_YES;
446 }
447
448 /**
449  * Method that assembles our hostlist advertisement message
450  * @param peer peer to send the hostlist advertisement
451  */
452 static size_t
453 adv_create_message ( const struct GNUNET_PeerIdentity * peer )
454
455 {
456   size_t length  = 0;
457   size_t size    = 0;
458   unsigned long long port;
459
460   char *uri;
461   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
462   char *protocol = "http://";
463   char *port_s = GNUNET_malloc(6 * sizeof(char));
464
465   if (0 != gethostname (hostname, sizeof (hostname) - 1))
466   {
467     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
468         "Could not get system's hostname, unable to create advertisement message");
469     return GNUNET_NO;
470   }
471   if (-1 == GNUNET_CONFIGURATION_get_value_number (cfg,
472                                                    "HOSTLIST",
473                                                    "HTTPPORT",
474                                                    &port))
475     return GNUNET_SYSERR;
476
477   sprintf(port_s, "%llu", port);
478   length = strlen(hostname)+strlen(protocol)+strlen(port_s)+2;
479   size = (length+1) * sizeof (char);
480   uri = GNUNET_malloc(size);
481   uri = strcpy(uri, protocol);
482   uri = strcat(uri, hostname);
483   uri = strcat(uri, ":");
484   uri = strcat(uri, port_s);
485   uri = strcat(uri, "/");
486   if ( length < 255);
487     strcpy(hostlist_uri,uri);
488
489   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Address to obtain hostlist: %s\n", hostlist_uri);
490
491   if ( ( size + sizeof( struct GNUNET_HOSTLIST_ADV_Message )) > GNUNET_SERVER_MAX_MESSAGE_SIZE)
492     {
493       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
494           "Advertisement message is bigger than GNUNET allows");
495       return GNUNET_NO;
496     }
497
498   /* Request core to transmit message to peer */
499   size = size + sizeof ( struct GNUNET_HOSTLIST_ADV_Message );
500   adv_transmit_message(peer, size);
501
502   GNUNET_free ( port_s );
503   GNUNET_free ( uri );
504
505   return GNUNET_OK;
506 }
507
508 /**
509  * Method called whenever a given peer connects.
510  *
511  * @param cls closure
512  * @param peer peer identity this notification is about
513  * @param latency reported latency of the connection with 'other'
514  * @param distance reported distance (DV) to 'other'
515  */
516 static void
517 connect_handler (void *cls,
518                  const struct
519                  GNUNET_PeerIdentity * peer,
520                  struct GNUNET_TIME_Relative latency,
521                  uint32_t distance)
522 {
523   if ( !advertising )
524     return;
525
526   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527               "A new peer connected to the server, preparing to send hostlist advertisement\n");
528   /* create a new advertisement message */
529   if ( (GNUNET_OK != adv_create_message(peer)))
530   {
531     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
532                 _(" GNUNET_OK Could not create a hostlist advertisement message, impossible to advertise hostlist\n"));
533     return;
534   }
535 }
536
537
538 /**
539  * Method called whenever a given peer disconnects.
540  *
541  * @param cls closure
542  * @param peer peer identity this notification is about
543  */
544 static void
545 disconnect_handler (void *cls,
546                     const struct
547                     GNUNET_PeerIdentity * peer)
548 {
549
550 }
551
552
553 /**
554  * Function that queries MHD's select sets and
555  * starts the task waiting for them.
556  */
557 static GNUNET_SCHEDULER_TaskIdentifier
558 prepare_daemon (struct MHD_Daemon *daemon_handle);
559
560 /**
561  * Call MHD to process pending requests and then go back
562  * and schedule the next run.
563  */
564 static void
565 run_daemon (void *cls,
566             const struct GNUNET_SCHEDULER_TaskContext *tc)
567 {
568   struct MHD_Daemon *daemon_handle = cls;
569
570   if (daemon_handle == daemon_handle_v4)
571     hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK;
572   else
573     hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK;
574
575   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
576     return;    
577   GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
578   if (daemon_handle == daemon_handle_v4)
579     hostlist_task_v4 = prepare_daemon (daemon_handle);
580   else
581     hostlist_task_v6 = prepare_daemon (daemon_handle);
582 }
583
584
585 /**
586  * Function that queries MHD's select sets and
587  * starts the task waiting for them.
588  */
589 static GNUNET_SCHEDULER_TaskIdentifier
590 prepare_daemon (struct MHD_Daemon *daemon_handle)
591 {
592   GNUNET_SCHEDULER_TaskIdentifier ret;
593   fd_set rs;
594   fd_set ws;
595   fd_set es;
596   struct GNUNET_NETWORK_FDSet *wrs;
597   struct GNUNET_NETWORK_FDSet *wws;
598   struct GNUNET_NETWORK_FDSet *wes;
599   int max;
600   unsigned long long timeout;
601   int haveto;
602   struct GNUNET_TIME_Relative tv;
603   
604   FD_ZERO(&rs);
605   FD_ZERO(&ws);
606   FD_ZERO(&es);
607   wrs = GNUNET_NETWORK_fdset_create ();
608   wes = GNUNET_NETWORK_fdset_create ();
609   wws = GNUNET_NETWORK_fdset_create ();
610   max = -1;
611   GNUNET_assert (MHD_YES ==
612                  MHD_get_fdset (daemon_handle,
613                                 &rs,
614                                 &ws,
615                                 &es,
616                                 &max));
617   haveto = MHD_get_timeout (daemon_handle, &timeout);
618   if (haveto == MHD_YES)
619     tv.value = (uint64_t) timeout;
620   else
621     tv = GNUNET_TIME_UNIT_FOREVER_REL;
622   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
623   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
624   GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
625   ret = GNUNET_SCHEDULER_add_select (sched,
626                                      GNUNET_SCHEDULER_PRIORITY_HIGH,
627                                      GNUNET_SCHEDULER_NO_TASK,
628                                      tv,
629                                      wrs,
630                                      wws,
631                                      &run_daemon,
632                                      daemon_handle);
633   GNUNET_NETWORK_fdset_destroy (wrs);
634   GNUNET_NETWORK_fdset_destroy (wws);
635   GNUNET_NETWORK_fdset_destroy (wes);
636   return ret;
637 }
638
639
640
641 /**
642  * Start server offering our hostlist.
643  *
644  * @return GNUNET_OK on success
645  */
646 int
647 GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c,
648                               struct GNUNET_SCHEDULER_Handle *s,
649                               struct GNUNET_STATISTICS_Handle *st,
650                               struct GNUNET_CORE_Handle *co,
651                               GNUNET_CORE_ConnectEventHandler *server_ch,
652                               GNUNET_CORE_DisconnectEventHandler *server_dh,
653                               int advertise)
654 {
655   unsigned long long port;
656
657   advertising = advertise;
658   if  ( !advertising )
659     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660               "Advertising not enabled on this hostlist server\n");
661   else
662     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663               "Advertising enabled on this hostlist server\n");
664   sched = s;
665   cfg = c;
666   stats = st;
667   if (-1 == GNUNET_CONFIGURATION_get_value_number (cfg,
668                                                    "HOSTLIST",
669                                                    "HTTPPORT", 
670                                                    &port))
671     return GNUNET_SYSERR;
672   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
673               _("Hostlist service starts on port %llu\n"),
674               port);
675   daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 
676 #if DEBUG_HOSTLIST_SERVER
677                                        | MHD_USE_DEBUG
678 #endif
679                                        ,
680                                        (unsigned short) port,
681                                        &accept_policy_callback,
682                                        NULL,
683                                        &access_handler_callback,
684                                        NULL,
685                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
686                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
687                                        MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
688                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
689                                        MHD_OPTION_END);
690   daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG
691 #if DEBUG_HOSTLIST_SERVER
692                                        | MHD_USE_DEBUG
693 #endif
694                                        ,
695                                        (unsigned short) port,
696                                        &accept_policy_callback,
697                                        NULL,
698                                        &access_handler_callback,
699                                        NULL,
700                                        MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 16,
701                                        MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
702                                        MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
703                                        MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
704                                        MHD_OPTION_END);
705
706   if ( (daemon_handle_v6 == NULL) &&
707        (daemon_handle_v4 == NULL) )
708     {
709       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
710                   _("Could not start hostlist HTTP server on port %u\n"),
711                   (unsigned short) port);
712       return GNUNET_SYSERR;    
713     }
714
715   core=co;
716
717   *server_ch = &connect_handler;
718   *server_dh = &disconnect_handler;
719
720   if (daemon_handle_v4 != NULL)
721     hostlist_task_v4 = prepare_daemon (daemon_handle_v4);
722   if (daemon_handle_v6 != NULL)
723     hostlist_task_v6 = prepare_daemon (daemon_handle_v6);
724   response_task = GNUNET_SCHEDULER_add_now (sched,
725                                             &update_response,
726                                             NULL);
727   return GNUNET_OK;
728 }
729
730 /**
731  * Stop server offering our hostlist.
732  */
733 void
734 GNUNET_HOSTLIST_server_stop ()
735 {
736 #if DEBUG_HOSTLIST_SERVER
737   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
738               "Hostlist server shutdown\n");
739 #endif
740   if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6)
741     {
742       GNUNET_SCHEDULER_cancel (sched, hostlist_task_v6);
743       hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK;
744     }
745   if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4)
746     {
747       GNUNET_SCHEDULER_cancel (sched, hostlist_task_v4);
748       hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK;
749     }
750   if (pitr != NULL)
751     {
752       GNUNET_PEERINFO_iterate_cancel (pitr);
753       pitr = NULL;
754     }
755   if (GNUNET_SCHEDULER_NO_TASK != response_task)
756     {
757       GNUNET_SCHEDULER_cancel (sched, response_task);
758       response_task = GNUNET_SCHEDULER_NO_TASK;
759     }
760   if (NULL != daemon_handle_v4)
761     {
762       MHD_stop_daemon (daemon_handle_v4);
763       daemon_handle_v4 = NULL;
764     }
765   if (NULL != daemon_handle_v6)
766     {
767       MHD_stop_daemon (daemon_handle_v6);
768       daemon_handle_v6 = NULL;
769     }
770   if (response != NULL)
771     {
772       MHD_destroy_response (response);
773       response = NULL;
774     }
775 }
776
777 /* end of hostlist-server.c */