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