peerinfo_api.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2001-2014 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 peerinfo/peerinfo_api.c
  18. * @brief API to access peerinfo service
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_protocols.h"
  24. #include "peerinfo.h"
  25. #define LOG(kind,...) GNUNET_log_from (kind, "peerinfo-api",__VA_ARGS__)
  26. /**
  27. * Context for an iteration request.
  28. */
  29. struct GNUNET_PEERINFO_IteratorContext
  30. {
  31. /**
  32. * Kept in a DLL.
  33. */
  34. struct GNUNET_PEERINFO_IteratorContext *next;
  35. /**
  36. * Kept in a DLL.
  37. */
  38. struct GNUNET_PEERINFO_IteratorContext *prev;
  39. /**
  40. * Handle to the PEERINFO service.
  41. */
  42. struct GNUNET_PEERINFO_Handle *h;
  43. /**
  44. * Function to call with the results.
  45. */
  46. GNUNET_PEERINFO_Processor callback;
  47. /**
  48. * Closure for @e callback.
  49. */
  50. void *callback_cls;
  51. /**
  52. * Peer we are interested in (only valid if iteration was restricted to one peer).
  53. */
  54. struct GNUNET_PeerIdentity peer;
  55. /**
  56. * Is @e peer set?
  57. */
  58. int have_peer;
  59. /**
  60. * Only include friends in reply?
  61. */
  62. int include_friend_only;
  63. };
  64. /**
  65. * Handle to the peerinfo service.
  66. */
  67. struct GNUNET_PEERINFO_Handle
  68. {
  69. /**
  70. * Our configuration.
  71. */
  72. const struct GNUNET_CONFIGURATION_Handle *cfg;
  73. /**
  74. * Connection to the service.
  75. */
  76. struct GNUNET_MQ_Handle *mq;
  77. /**
  78. * Head of iterator DLL.
  79. */
  80. struct GNUNET_PEERINFO_IteratorContext *ic_head;
  81. /**
  82. * Tail of iterator DLL.
  83. */
  84. struct GNUNET_PEERINFO_IteratorContext *ic_tail;
  85. /**
  86. * ID for a reconnect task.
  87. */
  88. struct GNUNET_SCHEDULER_Task *r_task;
  89. };
  90. /**
  91. * Close the existing connection to PEERINFO and reconnect.
  92. *
  93. * @param h handle to the service
  94. */
  95. static void
  96. reconnect (struct GNUNET_PEERINFO_Handle *h);
  97. /**
  98. * Connect to the peerinfo service.
  99. *
  100. * @param cfg configuration to use
  101. * @return NULL on error (configuration related, actual connection
  102. * establishment may happen asynchronously).
  103. */
  104. struct GNUNET_PEERINFO_Handle *
  105. GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
  106. {
  107. struct GNUNET_PEERINFO_Handle *h;
  108. h = GNUNET_new (struct GNUNET_PEERINFO_Handle);
  109. h->cfg = cfg;
  110. reconnect (h);
  111. if (NULL == h->mq)
  112. {
  113. GNUNET_free (h);
  114. return NULL;
  115. }
  116. return h;
  117. }
  118. /**
  119. * Disconnect from the peerinfo service. Note that all iterators must
  120. * have completed or have been cancelled by the time this function is
  121. * called (otherwise, calling this function is a serious error).
  122. * Furthermore, if #GNUNET_PEERINFO_add_peer() operations are still
  123. * pending, they will be cancelled silently on disconnect.
  124. *
  125. * @param h handle to disconnect
  126. */
  127. void
  128. GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
  129. {
  130. struct GNUNET_PEERINFO_IteratorContext *ic;
  131. while (NULL != (ic = h->ic_head))
  132. {
  133. GNUNET_CONTAINER_DLL_remove (h->ic_head,
  134. h->ic_tail,
  135. ic);
  136. GNUNET_free (ic);
  137. }
  138. if (NULL != h->mq)
  139. {
  140. GNUNET_MQ_destroy (h->mq);
  141. h->mq = NULL;
  142. }
  143. if (NULL != h->r_task)
  144. {
  145. GNUNET_SCHEDULER_cancel (h->r_task);
  146. h->r_task = NULL;
  147. }
  148. GNUNET_free (h);
  149. }
  150. /**
  151. * Task scheduled to re-try connecting to the peerinfo service.
  152. *
  153. * @param cls the `struct GNUNET_PEERINFO_Handle *`
  154. */
  155. static void
  156. reconnect_task (void *cls)
  157. {
  158. struct GNUNET_PEERINFO_Handle *h = cls;
  159. h->r_task = NULL;
  160. reconnect (h);
  161. }
  162. /**
  163. * We encountered an error, reconnect to the PEERINFO service.
  164. *
  165. * @param h handle to reconnect
  166. */
  167. static void
  168. do_reconnect (struct GNUNET_PEERINFO_Handle *h)
  169. {
  170. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  171. GNUNET_MQ_destroy (h->mq);
  172. h->mq = NULL;
  173. if (NULL != ic)
  174. {
  175. GNUNET_CONTAINER_DLL_remove (h->ic_head,
  176. h->ic_tail,
  177. ic);
  178. if (NULL != ic->callback)
  179. ic->callback (ic->callback_cls,
  180. NULL,
  181. NULL,
  182. _("Failed to receive response from `PEERINFO' service."));
  183. GNUNET_free (ic);
  184. }
  185. h->r_task = GNUNET_SCHEDULER_add_now (&reconnect_task,
  186. h);
  187. }
  188. /**
  189. * We got a disconnect after asking regex to do the announcement.
  190. * Retry.
  191. *
  192. * @param cls the `struct GNUNET_PEERINFO_Handle` to retry
  193. * @param error error code
  194. */
  195. static void
  196. mq_error_handler (void *cls,
  197. enum GNUNET_MQ_Error error)
  198. {
  199. struct GNUNET_PEERINFO_Handle *h = cls;
  200. do_reconnect (h);
  201. }
  202. /**
  203. * Function called when we receive an info message. Check it is
  204. * well-formed.
  205. *
  206. * @param cls closure
  207. * @param im message received
  208. * @return #GNUNET_OK if the message is OK
  209. */
  210. static int
  211. check_info (void *cls,
  212. const struct InfoMessage *im)
  213. {
  214. struct GNUNET_PEERINFO_Handle *h = cls;
  215. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  216. uint16_t ms = ntohs (im->header.size) - sizeof (*im);
  217. if (0 != ntohl (im->reserved))
  218. {
  219. GNUNET_break (0);
  220. return GNUNET_SYSERR;
  221. }
  222. if (NULL == ic)
  223. {
  224. /* didn't expect a response, bad */
  225. GNUNET_break (0);
  226. return GNUNET_SYSERR;
  227. }
  228. if ( (GNUNET_YES == ic->have_peer) &&
  229. (0 != GNUNET_memcmp (&ic->peer,
  230. &im->peer)) )
  231. {
  232. /* bogus message (from a different iteration call?); out of sequence! */
  233. LOG (GNUNET_ERROR_TYPE_ERROR,
  234. "Received HELLO for peer `%s', expected peer `%s'\n",
  235. GNUNET_i2s (&im->peer),
  236. GNUNET_i2s (&ic->peer));
  237. GNUNET_break (0);
  238. return GNUNET_SYSERR;
  239. }
  240. if (ms > sizeof (struct GNUNET_MessageHeader))
  241. {
  242. const struct GNUNET_HELLO_Message *hello;
  243. struct GNUNET_PeerIdentity id;
  244. hello = (const struct GNUNET_HELLO_Message *) &im[1];
  245. if (ms != GNUNET_HELLO_size (hello))
  246. {
  247. /* malformed message */
  248. GNUNET_break (0);
  249. return GNUNET_SYSERR;
  250. }
  251. if (GNUNET_OK !=
  252. GNUNET_HELLO_get_id (hello,
  253. &id))
  254. {
  255. /* malformed message */
  256. GNUNET_break (0);
  257. return GNUNET_SYSERR;
  258. }
  259. if (0 != GNUNET_memcmp (&im->peer,
  260. &id))
  261. {
  262. /* malformed message */
  263. GNUNET_break (0);
  264. return GNUNET_SYSERR;
  265. }
  266. }
  267. else if (0 != ms)
  268. {
  269. /* malformed message */
  270. GNUNET_break (0);
  271. return GNUNET_SYSERR;
  272. }
  273. return GNUNET_OK;
  274. }
  275. /**
  276. * Handle info message.
  277. *
  278. * @param cls closure
  279. * @param im message received
  280. */
  281. static void
  282. handle_info (void *cls,
  283. const struct InfoMessage *im)
  284. {
  285. struct GNUNET_PEERINFO_Handle *h = cls;
  286. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  287. const struct GNUNET_HELLO_Message *hello = NULL;
  288. uint16_t ms;
  289. ms = ntohs (im->header.size);
  290. if (ms > sizeof (struct InfoMessage))
  291. hello = (const struct GNUNET_HELLO_Message *) &im[1];
  292. if (NULL != ic->callback)
  293. ic->callback (ic->callback_cls,
  294. &im->peer,
  295. hello,
  296. NULL);
  297. }
  298. /**
  299. * Send the next IC request at the head of the queue.
  300. *
  301. * @param h handle
  302. */
  303. static void
  304. send_ic_request (struct GNUNET_PEERINFO_Handle *h)
  305. {
  306. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  307. struct GNUNET_MQ_Envelope *env;
  308. struct ListAllPeersMessage *lapm;
  309. struct ListPeerMessage *lpm;
  310. if (NULL == ic)
  311. {
  312. GNUNET_break (0);
  313. return;
  314. }
  315. if (NULL == h->mq)
  316. {
  317. GNUNET_break (0);
  318. return;
  319. }
  320. if (GNUNET_NO == ic->have_peer)
  321. {
  322. LOG (GNUNET_ERROR_TYPE_DEBUG,
  323. "Requesting list of peers from PEERINFO service\n");
  324. env = GNUNET_MQ_msg (lapm,
  325. GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
  326. lapm->include_friend_only = htonl (ic->include_friend_only);
  327. }
  328. else
  329. {
  330. LOG (GNUNET_ERROR_TYPE_DEBUG,
  331. "Requesting information on peer `%s' from PEERINFO service\n",
  332. GNUNET_i2s (&ic->peer));
  333. env = GNUNET_MQ_msg (lpm,
  334. GNUNET_MESSAGE_TYPE_PEERINFO_GET);
  335. lpm->include_friend_only = htonl (ic->include_friend_only);
  336. lpm->peer = ic->peer;
  337. }
  338. GNUNET_MQ_send (h->mq,
  339. env);
  340. }
  341. /**
  342. * Type of a function to call when we receive a message from the
  343. * service. Call the iterator with the result and (if applicable)
  344. * continue to receive more messages or trigger processing the next
  345. * event (if applicable).
  346. *
  347. * @param cls closure
  348. * @param msg message received, NULL on timeout or fatal error
  349. */
  350. static void
  351. handle_end_iteration (void *cls,
  352. const struct GNUNET_MessageHeader *msg)
  353. {
  354. struct GNUNET_PEERINFO_Handle *h = cls;
  355. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  356. if (NULL == ic)
  357. {
  358. /* didn't expect a response, reconnect */
  359. GNUNET_break (0);
  360. reconnect (h);
  361. return;
  362. }
  363. LOG (GNUNET_ERROR_TYPE_DEBUG,
  364. "Received end of list of peers from PEERINFO service\n");
  365. GNUNET_CONTAINER_DLL_remove (h->ic_head,
  366. h->ic_tail,
  367. ic);
  368. if (NULL != h->ic_head)
  369. send_ic_request (h);
  370. if (NULL != ic->callback)
  371. ic->callback (ic->callback_cls,
  372. NULL,
  373. NULL,
  374. NULL);
  375. GNUNET_free (ic);
  376. }
  377. /**
  378. * Close the existing connection to PEERINFO and reconnect.
  379. *
  380. * @param h handle to the service
  381. */
  382. static void
  383. reconnect (struct GNUNET_PEERINFO_Handle *h)
  384. {
  385. struct GNUNET_MQ_MessageHandler handlers[] = {
  386. GNUNET_MQ_hd_var_size (info,
  387. GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
  388. struct InfoMessage,
  389. h),
  390. GNUNET_MQ_hd_fixed_size (end_iteration,
  391. GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
  392. struct GNUNET_MessageHeader,
  393. h),
  394. GNUNET_MQ_handler_end ()
  395. };
  396. if (NULL != h->r_task)
  397. {
  398. GNUNET_SCHEDULER_cancel (h->r_task);
  399. h->r_task = NULL;
  400. }
  401. if (NULL != h->mq)
  402. {
  403. GNUNET_MQ_destroy (h->mq);
  404. h->mq = NULL;
  405. }
  406. h->mq = GNUNET_CLIENT_connect (h->cfg,
  407. "peerinfo",
  408. handlers,
  409. &mq_error_handler,
  410. h);
  411. if (NULL != h->ic_head)
  412. send_ic_request (h);
  413. }
  414. /**
  415. * Call a method for each known matching host. The callback method
  416. * will be invoked once for each matching host and then finally once
  417. * with a NULL pointer. After that final invocation, the iterator
  418. * context must no longer be used.
  419. *
  420. * Instead of calling this function with `peer == NULL` it is often
  421. * better to use #GNUNET_PEERINFO_notify().
  422. *
  423. * @param h handle to the peerinfo service
  424. * @param include_friend_only include HELLO messages for friends only
  425. * @param peer restrict iteration to this peer only (can be NULL)
  426. * @param callback the method to call for each peer
  427. * @param callback_cls closure for @a callback
  428. * @return iterator context
  429. */
  430. struct GNUNET_PEERINFO_IteratorContext *
  431. GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
  432. int include_friend_only,
  433. const struct GNUNET_PeerIdentity *peer,
  434. GNUNET_PEERINFO_Processor callback,
  435. void *callback_cls)
  436. {
  437. struct GNUNET_PEERINFO_IteratorContext *ic;
  438. ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
  439. ic->h = h;
  440. ic->include_friend_only = include_friend_only;
  441. ic->callback = callback;
  442. ic->callback_cls = callback_cls;
  443. if (NULL != peer)
  444. {
  445. ic->have_peer = GNUNET_YES;
  446. ic->peer = *peer;
  447. }
  448. GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
  449. h->ic_tail,
  450. ic);
  451. if (h->ic_head == ic)
  452. send_ic_request (h);
  453. return ic;
  454. }
  455. /**
  456. * Cancel an iteration over peer information.
  457. *
  458. * @param ic context of the iterator to cancel
  459. */
  460. void
  461. GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
  462. {
  463. struct GNUNET_PEERINFO_Handle *h = ic->h;
  464. ic->callback = NULL;
  465. if (ic == h->ic_head)
  466. return;
  467. GNUNET_CONTAINER_DLL_remove (h->ic_head,
  468. h->ic_tail,
  469. ic);
  470. GNUNET_free (ic);
  471. }
  472. /**
  473. * Add a host to the persistent list. This method operates in
  474. * semi-reliable mode: if the transmission is not completed by
  475. * the time #GNUNET_PEERINFO_disconnect() is called, it will be
  476. * aborted. Furthermore, if a second HELLO is added for the
  477. * same peer before the first one was transmitted, PEERINFO may
  478. * merge the two HELLOs prior to transmission to the service.
  479. *
  480. * @param h handle to the peerinfo service
  481. * @param hello the verified (!) HELLO message
  482. * @param cont continuation to call when done, NULL is allowed
  483. * @param cont_cls closure for @a cont
  484. * @return handle to cancel add operation; all pending
  485. * 'add' operations will be cancelled automatically
  486. * on disconnect, so it is not necessary to keep this
  487. * handle (unless @a cont is NULL and at some point
  488. * calling @a cont must be prevented)
  489. */
  490. struct GNUNET_MQ_Envelope *
  491. GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
  492. const struct GNUNET_HELLO_Message *hello,
  493. GNUNET_SCHEDULER_TaskCallback cont,
  494. void *cont_cls)
  495. {
  496. struct GNUNET_MQ_Envelope *env;
  497. struct GNUNET_PeerIdentity peer;
  498. if (NULL == h->mq)
  499. return NULL;
  500. GNUNET_assert (GNUNET_OK ==
  501. GNUNET_HELLO_get_id (hello,
  502. &peer));
  503. LOG (GNUNET_ERROR_TYPE_DEBUG,
  504. "Adding peer `%s' to PEERINFO database\n",
  505. GNUNET_i2s (&peer));
  506. env = GNUNET_MQ_msg_copy ((const struct GNUNET_MessageHeader *) hello);
  507. if (NULL != cont)
  508. GNUNET_MQ_notify_sent (env,
  509. cont,
  510. cont_cls);
  511. GNUNET_MQ_send (h->mq,
  512. env);
  513. return env;
  514. }
  515. /* end of peerinfo_api.c */