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