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