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