aboutsummaryrefslogtreecommitdiff
path: root/src/hostlist/gnunet-daemon-hostlist_server.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2014-06-03 08:41:00 +0000
committerChristian Grothoff <christian@grothoff.org>2014-06-03 08:41:00 +0000
commitaf4dff0ff8a129c05c75180446b691a0b2cd74c7 (patch)
treec3c02b821df02ea396e64a9b9a06ea9e9e85553b /src/hostlist/gnunet-daemon-hostlist_server.c
parentd7cf4a2a573e31c21630c08b038c2c648e5d3785 (diff)
downloadgnunet-af4dff0ff8a129c05c75180446b691a0b2cd74c7.tar.gz
gnunet-af4dff0ff8a129c05c75180446b691a0b2cd74c7.zip
-doxygen, code cleanup
Diffstat (limited to 'src/hostlist/gnunet-daemon-hostlist_server.c')
-rw-r--r--src/hostlist/gnunet-daemon-hostlist_server.c888
1 files changed, 888 insertions, 0 deletions
diff --git a/src/hostlist/gnunet-daemon-hostlist_server.c b/src/hostlist/gnunet-daemon-hostlist_server.c
new file mode 100644
index 000000000..8a7e747c6
--- /dev/null
+++ b/src/hostlist/gnunet-daemon-hostlist_server.c
@@ -0,0 +1,888 @@
1/*
2 This file is part of GNUnet.
3 (C) 2008, 2009, 2010, 2014 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/gnunet-daemon-hostlist_server.c
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 * @author David Barksdale
26 * @brief application to provide an integrated hostlist HTTP server
27 */
28#include "platform.h"
29#include <microhttpd.h>
30#include "gnunet-daemon-hostlist_server.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_peerinfo_service.h"
33#include "gnunet-daemon-hostlist.h"
34#include "gnunet_resolver_service.h"
35
36
37/**
38 * How long until our hostlist advertisment transmission via CORE should
39 * time out?
40 */
41#define GNUNET_ADV_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
42
43
44/**
45 * Handle to the HTTP server as provided by libmicrohttpd for IPv6.
46 */
47static struct MHD_Daemon *daemon_handle_v6;
48
49/**
50 * Handle to the HTTP server as provided by libmicrohttpd for IPv4.
51 */
52static struct MHD_Daemon *daemon_handle_v4;
53
54/**
55 * Our configuration.
56 */
57static const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59/**
60 * For keeping statistics.
61 */
62static struct GNUNET_STATISTICS_Handle *stats;
63
64/**
65 * Handle to the core service (NULL until we've connected to it).
66 */
67static struct GNUNET_CORE_Handle *core;
68
69/**
70 * Handle to the peerinfo notify service (NULL until we've connected to it).
71 */
72static struct GNUNET_PEERINFO_NotifyContext *notify;
73
74/**
75 * Our primary task for IPv4.
76 */
77static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4;
78
79/**
80 * Our primary task for IPv6.
81 */
82static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6;
83
84/**
85 * Our canonical response.
86 */
87static struct MHD_Response *response;
88
89/**
90 * Handle for accessing peerinfo service.
91 */
92static struct GNUNET_PEERINFO_Handle *peerinfo;
93
94/**
95 * Set if we are allowed to advertise our hostlist to others.
96 */
97static int advertising;
98
99/**
100 * Buffer for the hostlist address
101 */
102static char *hostlist_uri;
103
104
105/**
106 * Context for host processor.
107 */
108struct HostSet
109{
110 unsigned int size;
111
112 char *data;
113
114 struct GNUNET_PEERINFO_IteratorContext *pitr;
115};
116
117
118/**
119 * NULL if we are not currenlty iterating over peer information.
120 */
121static struct HostSet *builder;
122
123
124/**
125 * Function that assembles our response.
126 */
127static void
128finish_response ()
129{
130 if (NULL != response)
131 MHD_destroy_response (response);
132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
133 "Creating hostlist response with %u bytes\n",
134 (unsigned int) builder->size);
135 response =
136 MHD_create_response_from_data (builder->size, builder->data, MHD_YES,
137 MHD_NO);
138 if ((NULL == daemon_handle_v4) && (NULL == daemon_handle_v6))
139 {
140 MHD_destroy_response (response);
141 response = NULL;
142 }
143 GNUNET_STATISTICS_set (stats, gettext_noop ("bytes in hostlist"),
144 builder->size, GNUNET_YES);
145 GNUNET_free (builder);
146 builder = NULL;
147}
148
149
150/**
151 * Set @a cls to #GNUNET_YES (we have an address!).
152 *
153 * @param cls closure, an `int *`
154 * @param address the address (ignored)
155 * @param expiration expiration time (call is ignored if this is in the past)
156 * @return #GNUNET_SYSERR to stop iterating (unless expiration has occured)
157 */
158static int
159check_has_addr (void *cls,
160 const struct GNUNET_HELLO_Address *address,
161 struct GNUNET_TIME_Absolute expiration)
162{
163 int *arg = cls;
164
165 if (0 == GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us)
166 {
167 GNUNET_STATISTICS_update (stats,
168 gettext_noop ("expired addresses encountered"), 1,
169 GNUNET_YES);
170 return GNUNET_YES; /* ignore this address */
171 }
172 *arg = GNUNET_YES;
173 return GNUNET_SYSERR;
174}
175
176
177/**
178 * Callback that processes each of the known HELLOs for the
179 * hostlist response construction.
180 *
181 * @param cls closure, NULL
182 * @param peer id of the peer, NULL for last call
183 * @param hello hello message for the peer (can be NULL)
184 * @param error message
185 */
186static void
187host_processor (void *cls,
188 const struct GNUNET_PeerIdentity *peer,
189 const struct GNUNET_HELLO_Message *hello,
190 const char *err_msg)
191{
192 size_t old;
193 size_t s;
194 int has_addr;
195
196 if (NULL != err_msg)
197 {
198 GNUNET_assert (NULL == peer);
199 builder->pitr = NULL;
200 GNUNET_free_non_null (builder->data);
201 GNUNET_free (builder);
202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 _("Error in communication with PEERINFO service: %s\n"),
204 err_msg);
205 return;
206 }
207 if (NULL == peer)
208 {
209 builder->pitr = NULL;
210 finish_response ();
211 return;
212 }
213 if (NULL == hello)
214 return;
215 has_addr = GNUNET_NO;
216 GNUNET_HELLO_iterate_addresses (hello,
217 GNUNET_NO,
218 &check_has_addr,
219 &has_addr);
220 if (GNUNET_NO == has_addr)
221 {
222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223 "HELLO for peer `%4s' has no address, not suitable for hostlist!\n",
224 GNUNET_i2s (peer));
225 GNUNET_STATISTICS_update (stats,
226 gettext_noop
227 ("HELLOs without addresses encountered (ignored)"),
228 1, GNUNET_NO);
229 return;
230 }
231 old = builder->size;
232 s = GNUNET_HELLO_size (hello);
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "Received %u bytes of `%s' from peer `%s' for hostlist.\n",
235 (unsigned int) s,
236 "HELLO",
237 GNUNET_i2s (peer));
238 if ((old + s >= GNUNET_MAX_MALLOC_CHECKED) ||
239 (old + s >= MAX_BYTES_PER_HOSTLISTS))
240 {
241 GNUNET_STATISTICS_update (stats,
242 gettext_noop
243 ("bytes not included in hostlist (size limit)"),
244 s, GNUNET_NO);
245 return; /* too large, skip! */
246 }
247 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
248 "Adding peer `%s' to hostlist (%u bytes)\n",
249 GNUNET_i2s (peer),
250 (unsigned int) s);
251 GNUNET_array_grow (builder->data, builder->size, old + s);
252 memcpy (&builder->data[old], hello, s);
253}
254
255
256/**
257 * Hostlist access policy (very permissive, allows everything).
258 * Returns #MHD_NO only if we are not yet ready to serve.
259 *
260 * @param cls closure
261 * @param addr address information from the client
262 * @param addrlen length of @a addr
263 * @return #MHD_YES if connection is allowed, #MHD_NO if not (we are not ready)
264 */
265static int
266accept_policy_callback (void *cls,
267 const struct sockaddr *addr,
268 socklen_t addrlen)
269{
270 if (NULL == response)
271 {
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Received request for hostlist, but I am not yet ready; rejecting!\n");
274 return MHD_NO;
275 }
276 return MHD_YES; /* accept all */
277}
278
279
280/**
281 * Add headers to a request indicating that we allow Cross-Origin Resource
282 * Sharing.
283 *
284 * @param response response to add headers to
285 */
286static void
287add_cors_headers (struct MHD_Response *response)
288{
289 MHD_add_response_header (response,
290 "Access-Control-Allow-Origin",
291 "*");
292 MHD_add_response_header (response,
293 "Access-Control-Allow-Methods",
294 "GET, OPTIONS");
295 MHD_add_response_header (response,
296 "Access-Control-Max-Age",
297 "86400");
298}
299
300
301/**
302 * Main request handler.
303 *
304 * @param cls argument given together with the function
305 * pointer when the handler was registered with MHD
306 * @param url the requested url
307 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
308 * #MHD_HTTP_METHOD_PUT, etc.)
309 * @param version the HTTP version string (i.e.
310 * #MHD_HTTP_VERSION_1_1)
311 * @param upload_data the data being uploaded (excluding HEADERS,
312 * for a POST that fits into memory and that is encoded
313 * with a supported encoding, the POST data will NOT be
314 * given in upload_data and is instead available as
315 * part of #MHD_get_connection_values; very large POST
316 * data *will* be made available incrementally in
317 * @a upload_data)
318 * @param upload_data_size set initially to the size of the
319 * @a upload_data provided; the method must update this
320 * value to the number of bytes NOT processed;
321 * @param con_cls pointer that the callback can set to some
322 * address and that will be preserved by MHD for future
323 * calls for this request; since the access handler may
324 * be called many times (i.e., for a PUT/POST operation
325 * with plenty of upload data) this allows the application
326 * to easily associate some request-specific state.
327 * If necessary, this state can be cleaned up in the
328 * global #MHD_RequestCompletedCallback (which
329 * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
330 * Initially, `*con_cls` will be NULL.
331 * @return #MHD_YES if the connection was handled successfully,
332 * #MHD_NO if the socket must be closed due to a serios
333 * error while handling the request
334 */
335static int
336access_handler_callback (void *cls,
337 struct MHD_Connection *connection,
338 const char *url,
339 const char *method,
340 const char *version,
341 const char *upload_data,
342 size_t *upload_data_size,
343 void **con_cls)
344{
345 static int dummy;
346
347 /* CORS pre-flight request */
348 if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method))
349 {
350 struct MHD_Response *options_response;
351 int rc;
352
353 options_response = MHD_create_response_from_buffer (0, NULL,
354 MHD_RESPMEM_PERSISTENT);
355 add_cors_headers(options_response);
356 rc = MHD_queue_response (connection, MHD_HTTP_OK, options_response);
357 MHD_destroy_response (options_response);
358 return rc;
359 }
360 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
361 {
362 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
363 _("Refusing `%s' request to hostlist server\n"), method);
364 GNUNET_STATISTICS_update (stats,
365 gettext_noop
366 ("hostlist requests refused (not HTTP GET)"), 1,
367 GNUNET_YES);
368 return MHD_NO;
369 }
370 if (NULL == *con_cls)
371 {
372 (*con_cls) = &dummy;
373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
374 "Sending 100 CONTINUE reply\n");
375 return MHD_YES; /* send 100 continue */
376 }
377 if (0 != *upload_data_size)
378 {
379 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
380 _("Refusing `%s' request with %llu bytes of upload data\n"),
381 method, (unsigned long long) *upload_data_size);
382 GNUNET_STATISTICS_update (stats,
383 gettext_noop
384 ("hostlist requests refused (upload data)"), 1,
385 GNUNET_YES);
386 return MHD_NO; /* do not support upload data */
387 }
388 if (NULL == response)
389 {
390 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
391 _("Could not handle hostlist request since I do not have a response yet\n"));
392 GNUNET_STATISTICS_update (stats,
393 gettext_noop
394 ("hostlist requests refused (not ready)"), 1,
395 GNUNET_YES);
396 return MHD_NO; /* internal error, no response yet */
397 }
398 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
399 _("Received request for our hostlist\n"));
400 GNUNET_STATISTICS_update (stats,
401 gettext_noop ("hostlist requests processed"),
402 1, GNUNET_YES);
403 add_cors_headers (response);
404 return MHD_queue_response (connection, MHD_HTTP_OK, response);
405}
406
407
408/**
409 * Handler called by CORE when CORE is ready to transmit message
410 *
411 * @param cls closure
412 * @param size size of buffer to copy message to
413 * @param buf buffer to copy message to
414 * @return number of bytes copied to @a buf
415 */
416static size_t
417adv_transmit_ready (void *cls,
418 size_t size,
419 void *buf)
420{
421 static uint64_t hostlist_adv_count;
422 size_t transmission_size;
423 size_t uri_size; /* Including \0 termination! */
424 struct GNUNET_MessageHeader header;
425 char *cbuf;
426
427 if (NULL == buf)
428 {
429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
430 "Transmission failed, buffer invalid!\n");
431 return 0;
432 }
433 uri_size = strlen (hostlist_uri) + 1;
434 transmission_size = sizeof (struct GNUNET_MessageHeader) + uri_size;
435 header.type = htons (GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT);
436 header.size = htons (transmission_size);
437 GNUNET_assert (size >= transmission_size);
438 memcpy (buf, &header, sizeof (struct GNUNET_MessageHeader));
439 cbuf = buf;
440 memcpy (&cbuf[sizeof (struct GNUNET_MessageHeader)], hostlist_uri, uri_size);
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Sent advertisement message: Copied %u bytes into buffer!\n",
443 (unsigned int) transmission_size);
444 hostlist_adv_count++;
445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " # Sent advertisement message: %u\n",
446 hostlist_adv_count);
447 GNUNET_STATISTICS_update (stats,
448 gettext_noop ("# hostlist advertisements send"), 1,
449 GNUNET_NO);
450 return transmission_size;
451}
452
453
454/**
455 * Method called whenever a given peer connects.
456 *
457 * @param cls closure
458 * @param peer peer identity this notification is about
459 */
460static void
461connect_handler (void *cls,
462 const struct GNUNET_PeerIdentity *peer)
463{
464 size_t size;
465
466 if (!advertising)
467 return;
468 if (NULL == hostlist_uri)
469 return;
470 size = strlen (hostlist_uri) + 1;
471 if (size + sizeof (struct GNUNET_MessageHeader) >=
472 GNUNET_SERVER_MAX_MESSAGE_SIZE)
473 {
474 GNUNET_break (0);
475 return;
476 }
477 size += sizeof (struct GNUNET_MessageHeader);
478 if (NULL == core)
479 {
480 GNUNET_break (0);
481 return;
482 }
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "Asked CORE to transmit advertisement message with a size of %u bytes to peer `%s'\n",
485 size,
486 GNUNET_i2s (peer));
487 if (NULL ==
488 GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES,
489 GNUNET_CORE_PRIO_BEST_EFFORT,
490 GNUNET_ADV_TIMEOUT,
491 peer,
492 size,
493 &adv_transmit_ready, NULL))
494 {
495 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
496 _("Advertisement message could not be queued by core\n"));
497 }
498}
499
500
501/**
502 * Method called whenever a given peer disconnects.
503 *
504 * @param cls closure
505 * @param peer peer identity this notification is about
506 */
507static void
508disconnect_handler (void *cls,
509 const struct GNUNET_PeerIdentity *peer)
510{
511 /* nothing to do */
512}
513
514
515/**
516 * PEERINFO calls this function to let us know about a possible peer
517 * that we might want to connect to.
518 *
519 * @param cls closure (not used)
520 * @param peer potential peer to connect to
521 * @param hello HELLO for this peer (or NULL)
522 * @param err_msg NULL if successful, otherwise contains error message
523 */
524static void
525process_notify (void *cls,
526 const struct GNUNET_PeerIdentity *peer,
527 const struct GNUNET_HELLO_Message *hello,
528 const char *err_msg)
529{
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531 "Peerinfo is notifying us to rebuild our hostlist\n");
532 if (NULL != err_msg)
533 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
534 _("Error in communication with PEERINFO service: %s\n"),
535 err_msg);
536 if (NULL != builder)
537 {
538 /* restart re-build already in progress ... */
539 GNUNET_PEERINFO_iterate_cancel (builder->pitr);
540 GNUNET_free_non_null (builder->data);
541 builder->size = 0;
542 builder->data = NULL;
543 }
544 else
545 {
546 builder = GNUNET_new (struct HostSet);
547 }
548 GNUNET_assert (NULL != peerinfo);
549 builder->pitr =
550 GNUNET_PEERINFO_iterate (peerinfo, GNUNET_NO, NULL, GNUNET_TIME_UNIT_MINUTES,
551 &host_processor, NULL);
552}
553
554
555/**
556 * Function that queries MHD's select sets and
557 * starts the task waiting for them.
558 */
559static GNUNET_SCHEDULER_TaskIdentifier
560prepare_daemon (struct MHD_Daemon *daemon_handle);
561
562
563/**
564 * Call MHD to process pending requests and then go back
565 * and schedule the next run.
566 *
567 * @param cls the `struct MHD_Daemon` of the HTTP server to run
568 * @param tc scheduler context
569 */
570static void
571run_daemon (void *cls,
572 const struct GNUNET_SCHEDULER_TaskContext *tc)
573{
574 struct MHD_Daemon *daemon_handle = cls;
575
576 if (daemon_handle == daemon_handle_v4)
577 hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK;
578 else
579 hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK;
580
581 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
582 return;
583 GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
584 if (daemon_handle == daemon_handle_v4)
585 hostlist_task_v4 = prepare_daemon (daemon_handle);
586 else
587 hostlist_task_v6 = prepare_daemon (daemon_handle);
588}
589
590
591/**
592 * Function that queries MHD's select sets and
593 * starts the task waiting for them.
594 *
595 * @param daemon_handle HTTP server to prepare to run
596 */
597static GNUNET_SCHEDULER_TaskIdentifier
598prepare_daemon (struct MHD_Daemon *daemon_handle)
599{
600 GNUNET_SCHEDULER_TaskIdentifier ret;
601 fd_set rs;
602 fd_set ws;
603 fd_set es;
604 struct GNUNET_NETWORK_FDSet *wrs;
605 struct GNUNET_NETWORK_FDSet *wws;
606 int max;
607 MHD_UNSIGNED_LONG_LONG timeout;
608 int haveto;
609 struct GNUNET_TIME_Relative tv;
610
611 FD_ZERO (&rs);
612 FD_ZERO (&ws);
613 FD_ZERO (&es);
614 wrs = GNUNET_NETWORK_fdset_create ();
615 wws = GNUNET_NETWORK_fdset_create ();
616 max = -1;
617 GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
618 haveto = MHD_get_timeout (daemon_handle, &timeout);
619 if (haveto == MHD_YES)
620 tv.rel_value_us = (uint64_t) timeout * 1000LL;
621 else
622 tv = GNUNET_TIME_UNIT_FOREVER_REL;
623 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
624 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
625 ret =
626 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
627 tv, wrs, wws,
628 &run_daemon, daemon_handle);
629 GNUNET_NETWORK_fdset_destroy (wrs);
630 GNUNET_NETWORK_fdset_destroy (wws);
631 return ret;
632}
633
634
635/**
636 * Start server offering our hostlist.
637 *
638 * @param c configuration to use
639 * @param st statistics handle to use
640 * @param co core handle to use
641 * @param server_ch[OUT] set to handler for CORE connect events
642 * @param server_dh[OUT] set to handler for CORE disconnect events
643 * @param advertise #GNUNET_YES if we should advertise our hostlist
644 * @return #GNUNET_OK on success
645 */
646int
647GNUNET_HOSTLIST_server_start (const struct GNUNET_CONFIGURATION_Handle *c,
648 struct GNUNET_STATISTICS_Handle *st,
649 struct GNUNET_CORE_Handle *co,
650 GNUNET_CORE_ConnectEventHandler *server_ch,
651 GNUNET_CORE_DisconnectEventHandler *server_dh,
652 int advertise)
653{
654 unsigned long long port;
655 char *hostname;
656 char *ipv4;
657 char *ipv6;
658 size_t size;
659 struct in_addr i4;
660 struct in6_addr i6;
661 struct sockaddr_in v4;
662 struct sockaddr_in6 v6;
663 const struct sockaddr *sa4;
664 const struct sockaddr *sa6;
665
666 advertising = advertise;
667 if (! advertising)
668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
669 "Advertising not enabled on this hostlist server\n");
670 else
671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672 "Advertising enabled on this hostlist server\n");
673 cfg = c;
674 stats = st;
675 peerinfo = GNUNET_PEERINFO_connect (cfg);
676 if (NULL == peerinfo)
677 {
678 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
679 _("Could not access PEERINFO service. Exiting.\n"));
680 return GNUNET_SYSERR;
681 }
682 if (GNUNET_OK !=
683 GNUNET_CONFIGURATION_get_value_number (cfg,
684 "HOSTLIST",
685 "HTTPPORT",
686 &port))
687 return GNUNET_SYSERR;
688 if ((0 == port) || (port > UINT16_MAX))
689 {
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 _("Invalid port number %llu. Exiting.\n"),
692 port);
693 return GNUNET_SYSERR;
694 }
695
696 if (GNUNET_SYSERR ==
697 GNUNET_CONFIGURATION_get_value_string (cfg,
698 "HOSTLIST",
699 "EXTERNAL_DNS_NAME",
700 &hostname))
701 hostname = GNUNET_RESOLVER_local_fqdn_get ();
702 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
703 _("Hostlist service starts on %s:%llu\n"),
704 hostname, port);
705 if (NULL != hostname)
706 {
707 size = strlen (hostname);
708 if (size + 15 > MAX_URL_LEN)
709 {
710 GNUNET_break (0);
711 }
712 else
713 {
714 GNUNET_asprintf (&hostlist_uri,
715 "http://%s:%u/", hostname,
716 (unsigned int) port);
717 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
718 _("Address to obtain hostlist: `%s'\n"),
719 hostlist_uri);
720 }
721 GNUNET_free (hostname);
722 }
723
724 if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV4"))
725 {
726 GNUNET_break (GNUNET_OK ==
727 GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST",
728 "BINDTOIP", &ipv4));
729 }
730 else
731 ipv4 = NULL;
732 if (GNUNET_CONFIGURATION_have_value (cfg, "HOSTLIST", "BINDTOIPV6"))
733 {
734 GNUNET_break (GNUNET_OK ==
735 GNUNET_CONFIGURATION_get_value_string (cfg, "HOSTLIST",
736 "BINDTOIP", &ipv6));
737 }
738 else
739 ipv6 = NULL;
740 sa4 = NULL;
741 if (NULL != ipv4)
742 {
743 if (1 == inet_pton (AF_INET, ipv4, &i4))
744 {
745 memset (&v4, 0, sizeof (v4));
746 v4.sin_family = AF_INET;
747 v4.sin_addr = i4;
748 v4.sin_port = htons (port);
749#if HAVE_SOCKADDR_IN_SIN_LEN
750 v4.sin_len = sizeof (v4);
751#endif
752 sa4 = (const struct sockaddr *) &v4;
753 }
754 else
755 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
756 _("`%s' is not a valid IPv4 address! Ignoring BINDTOIPV4.\n"),
757 ipv4);
758 GNUNET_free (ipv4);
759 }
760 sa6 = NULL;
761 if (NULL != ipv6)
762 {
763 if (1 == inet_pton (AF_INET6, ipv6, &i6))
764 {
765 memset (&v6, 0, sizeof (v6));
766 v6.sin6_family = AF_INET6;
767 v6.sin6_addr = i6;
768 v6.sin6_port = htons (port);
769#if HAVE_SOCKADDR_IN_SIN_LEN
770 v6.sin6_len = sizeof (v6);
771#endif
772 sa6 = (const struct sockaddr *) &v6;
773 }
774 else
775 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
776 _("`%s' is not a valid IPv6 address! Ignoring BINDTOIPV6.\n"),
777 ipv6);
778 GNUNET_free (ipv6);
779 }
780
781 daemon_handle_v6 = MHD_start_daemon (MHD_USE_IPv6 | MHD_USE_DEBUG,
782 (uint16_t) port,
783 &accept_policy_callback, NULL,
784 &access_handler_callback, NULL,
785 MHD_OPTION_CONNECTION_LIMIT,
786 (unsigned int) 16,
787 MHD_OPTION_PER_IP_CONNECTION_LIMIT,
788 (unsigned int) 1,
789 MHD_OPTION_CONNECTION_TIMEOUT,
790 (unsigned int) 16,
791 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
792 (size_t) (16 * 1024),
793 MHD_OPTION_SOCK_ADDR,
794 sa6,
795 MHD_OPTION_END);
796 daemon_handle_v4 = MHD_start_daemon (MHD_NO_FLAG | MHD_USE_DEBUG,
797 (uint16_t) port,
798 &accept_policy_callback, NULL,
799 &access_handler_callback, NULL,
800 MHD_OPTION_CONNECTION_LIMIT,
801 (unsigned int) 16,
802 MHD_OPTION_PER_IP_CONNECTION_LIMIT,
803 (unsigned int) 1,
804 MHD_OPTION_CONNECTION_TIMEOUT,
805 (unsigned int) 16,
806 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
807 (size_t) (16 * 1024),
808 MHD_OPTION_SOCK_ADDR,
809 sa4,
810 MHD_OPTION_END);
811
812 if ( (NULL == daemon_handle_v6) &&
813 (NULL == daemon_handle_v4) )
814 {
815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
816 _("Could not start hostlist HTTP server on port %u\n"),
817 (unsigned short) port);
818 return GNUNET_SYSERR;
819 }
820
821 core = co;
822 *server_ch = &connect_handler;
823 *server_dh = &disconnect_handler;
824 if (NULL != daemon_handle_v4)
825 hostlist_task_v4 = prepare_daemon (daemon_handle_v4);
826 if (NULL != daemon_handle_v6)
827 hostlist_task_v6 = prepare_daemon (daemon_handle_v6);
828 notify = GNUNET_PEERINFO_notify (cfg, GNUNET_NO,
829 &process_notify, NULL);
830 return GNUNET_OK;
831}
832
833
834/**
835 * Stop server offering our hostlist.
836 */
837void
838GNUNET_HOSTLIST_server_stop ()
839{
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostlist server shutdown\n");
841 if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v6)
842 {
843 GNUNET_SCHEDULER_cancel (hostlist_task_v6);
844 hostlist_task_v6 = GNUNET_SCHEDULER_NO_TASK;
845 }
846 if (GNUNET_SCHEDULER_NO_TASK != hostlist_task_v4)
847 {
848 GNUNET_SCHEDULER_cancel (hostlist_task_v4);
849 hostlist_task_v4 = GNUNET_SCHEDULER_NO_TASK;
850 }
851 if (NULL != daemon_handle_v4)
852 {
853 MHD_stop_daemon (daemon_handle_v4);
854 daemon_handle_v4 = NULL;
855 }
856 if (NULL != daemon_handle_v6)
857 {
858 MHD_stop_daemon (daemon_handle_v6);
859 daemon_handle_v6 = NULL;
860 }
861 if (NULL != response)
862 {
863 MHD_destroy_response (response);
864 response = NULL;
865 }
866 if (NULL != notify)
867 {
868 GNUNET_PEERINFO_notify_cancel (notify);
869 notify = NULL;
870 }
871 if (NULL != builder)
872 {
873 GNUNET_PEERINFO_iterate_cancel (builder->pitr);
874 builder->pitr = NULL;
875 GNUNET_free_non_null (builder->data);
876 GNUNET_free (builder);
877 }
878 if (NULL != peerinfo)
879 {
880 GNUNET_PEERINFO_disconnect (peerinfo);
881 peerinfo = NULL;
882 }
883 cfg = NULL;
884 stats = NULL;
885 core = NULL;
886}
887
888/* end of gnunet-daemon-hostlist_server.c */