gnunet-daemon-hostlist_server.c 27 KB

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