diff options
author | Christian Grothoff <christian@grothoff.org> | 2014-06-03 08:41:00 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2014-06-03 08:41:00 +0000 |
commit | af4dff0ff8a129c05c75180446b691a0b2cd74c7 (patch) | |
tree | c3c02b821df02ea396e64a9b9a06ea9e9e85553b /src/hostlist/gnunet-daemon-hostlist_server.c | |
parent | d7cf4a2a573e31c21630c08b038c2c648e5d3785 (diff) | |
download | gnunet-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.c | 888 |
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 | */ | ||
47 | static struct MHD_Daemon *daemon_handle_v6; | ||
48 | |||
49 | /** | ||
50 | * Handle to the HTTP server as provided by libmicrohttpd for IPv4. | ||
51 | */ | ||
52 | static struct MHD_Daemon *daemon_handle_v4; | ||
53 | |||
54 | /** | ||
55 | * Our configuration. | ||
56 | */ | ||
57 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
58 | |||
59 | /** | ||
60 | * For keeping statistics. | ||
61 | */ | ||
62 | static struct GNUNET_STATISTICS_Handle *stats; | ||
63 | |||
64 | /** | ||
65 | * Handle to the core service (NULL until we've connected to it). | ||
66 | */ | ||
67 | static struct GNUNET_CORE_Handle *core; | ||
68 | |||
69 | /** | ||
70 | * Handle to the peerinfo notify service (NULL until we've connected to it). | ||
71 | */ | ||
72 | static struct GNUNET_PEERINFO_NotifyContext *notify; | ||
73 | |||
74 | /** | ||
75 | * Our primary task for IPv4. | ||
76 | */ | ||
77 | static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v4; | ||
78 | |||
79 | /** | ||
80 | * Our primary task for IPv6. | ||
81 | */ | ||
82 | static GNUNET_SCHEDULER_TaskIdentifier hostlist_task_v6; | ||
83 | |||
84 | /** | ||
85 | * Our canonical response. | ||
86 | */ | ||
87 | static struct MHD_Response *response; | ||
88 | |||
89 | /** | ||
90 | * Handle for accessing peerinfo service. | ||
91 | */ | ||
92 | static struct GNUNET_PEERINFO_Handle *peerinfo; | ||
93 | |||
94 | /** | ||
95 | * Set if we are allowed to advertise our hostlist to others. | ||
96 | */ | ||
97 | static int advertising; | ||
98 | |||
99 | /** | ||
100 | * Buffer for the hostlist address | ||
101 | */ | ||
102 | static char *hostlist_uri; | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Context for host processor. | ||
107 | */ | ||
108 | struct 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 | */ | ||
121 | static struct HostSet *builder; | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Function that assembles our response. | ||
126 | */ | ||
127 | static void | ||
128 | finish_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 | */ | ||
158 | static int | ||
159 | check_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 | */ | ||
186 | static void | ||
187 | host_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 | */ | ||
265 | static int | ||
266 | accept_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 | */ | ||
286 | static void | ||
287 | add_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 | */ | ||
335 | static int | ||
336 | access_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 | */ | ||
416 | static size_t | ||
417 | adv_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 | */ | ||
460 | static void | ||
461 | connect_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 | */ | ||
507 | static void | ||
508 | disconnect_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 | */ | ||
524 | static void | ||
525 | process_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 | */ | ||
559 | static GNUNET_SCHEDULER_TaskIdentifier | ||
560 | prepare_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 | */ | ||
570 | static void | ||
571 | run_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 | */ | ||
597 | static GNUNET_SCHEDULER_TaskIdentifier | ||
598 | prepare_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 | */ | ||
646 | int | ||
647 | GNUNET_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 | */ | ||
837 | void | ||
838 | GNUNET_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 */ | ||