gnunet-daemon-hostlist_server.c 26 KB

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