peerinfo_api.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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 != memcmp (&ic->peer,
  230. &im->peer,
  231. sizeof (struct GNUNET_PeerIdentity))) )
  232. {
  233. /* bogus message (from a different iteration call?); out of sequence! */
  234. LOG (GNUNET_ERROR_TYPE_ERROR,
  235. "Received HELLO for peer `%s', expected peer `%s'\n",
  236. GNUNET_i2s (&im->peer),
  237. GNUNET_i2s (&ic->peer));
  238. GNUNET_break (0);
  239. return GNUNET_SYSERR;
  240. }
  241. if (ms > sizeof (struct GNUNET_MessageHeader))
  242. {
  243. const struct GNUNET_HELLO_Message *hello;
  244. struct GNUNET_PeerIdentity id;
  245. hello = (const struct GNUNET_HELLO_Message *) &im[1];
  246. if (ms != GNUNET_HELLO_size (hello))
  247. {
  248. /* malformed message */
  249. GNUNET_break (0);
  250. return GNUNET_SYSERR;
  251. }
  252. if (GNUNET_OK !=
  253. GNUNET_HELLO_get_id (hello,
  254. &id))
  255. {
  256. /* malformed message */
  257. GNUNET_break (0);
  258. return GNUNET_SYSERR;
  259. }
  260. if (0 != memcmp (&im->peer,
  261. &id,
  262. sizeof (struct GNUNET_PeerIdentity)))
  263. {
  264. /* malformed message */
  265. GNUNET_break (0);
  266. return GNUNET_SYSERR;
  267. }
  268. }
  269. else if (0 != ms)
  270. {
  271. /* malformed message */
  272. GNUNET_break (0);
  273. return GNUNET_SYSERR;
  274. }
  275. return GNUNET_OK;
  276. }
  277. /**
  278. * Handle info message.
  279. *
  280. * @param cls closure
  281. * @param im message received
  282. */
  283. static void
  284. handle_info (void *cls,
  285. const struct InfoMessage *im)
  286. {
  287. struct GNUNET_PEERINFO_Handle *h = cls;
  288. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  289. const struct GNUNET_HELLO_Message *hello = NULL;
  290. uint16_t ms;
  291. ms = ntohs (im->header.size);
  292. if (ms > sizeof (struct InfoMessage))
  293. hello = (const struct GNUNET_HELLO_Message *) &im[1];
  294. if (NULL != ic->callback)
  295. ic->callback (ic->callback_cls,
  296. &im->peer,
  297. hello,
  298. NULL);
  299. }
  300. /**
  301. * Send the next IC request at the head of the queue.
  302. *
  303. * @param h handle
  304. */
  305. static void
  306. send_ic_request (struct GNUNET_PEERINFO_Handle *h)
  307. {
  308. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  309. struct GNUNET_MQ_Envelope *env;
  310. struct ListAllPeersMessage *lapm;
  311. struct ListPeerMessage *lpm;
  312. if (NULL == ic)
  313. {
  314. GNUNET_break (0);
  315. return;
  316. }
  317. if (NULL == h->mq)
  318. {
  319. GNUNET_break (0);
  320. return;
  321. }
  322. if (GNUNET_NO == ic->have_peer)
  323. {
  324. LOG (GNUNET_ERROR_TYPE_DEBUG,
  325. "Requesting list of peers from PEERINFO service\n");
  326. env = GNUNET_MQ_msg (lapm,
  327. GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
  328. lapm->include_friend_only = htonl (ic->include_friend_only);
  329. }
  330. else
  331. {
  332. LOG (GNUNET_ERROR_TYPE_DEBUG,
  333. "Requesting information on peer `%s' from PEERINFO service\n",
  334. GNUNET_i2s (&ic->peer));
  335. env = GNUNET_MQ_msg (lpm,
  336. GNUNET_MESSAGE_TYPE_PEERINFO_GET);
  337. lpm->include_friend_only = htonl (ic->include_friend_only);
  338. lpm->peer = ic->peer;
  339. }
  340. GNUNET_MQ_send (h->mq,
  341. env);
  342. }
  343. /**
  344. * Type of a function to call when we receive a message from the
  345. * service. Call the iterator with the result and (if applicable)
  346. * continue to receive more messages or trigger processing the next
  347. * event (if applicable).
  348. *
  349. * @param cls closure
  350. * @param msg message received, NULL on timeout or fatal error
  351. */
  352. static void
  353. handle_end_iteration (void *cls,
  354. const struct GNUNET_MessageHeader *msg)
  355. {
  356. struct GNUNET_PEERINFO_Handle *h = cls;
  357. struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
  358. if (NULL == ic)
  359. {
  360. /* didn't expect a response, reconnect */
  361. GNUNET_break (0);
  362. reconnect (h);
  363. return;
  364. }
  365. LOG (GNUNET_ERROR_TYPE_DEBUG,
  366. "Received end of list of peers from PEERINFO service\n");
  367. GNUNET_CONTAINER_DLL_remove (h->ic_head,
  368. h->ic_tail,
  369. ic);
  370. if (NULL != h->ic_head)
  371. send_ic_request (h);
  372. if (NULL != ic->callback)
  373. ic->callback (ic->callback_cls,
  374. NULL,
  375. NULL,
  376. NULL);
  377. GNUNET_free (ic);
  378. }
  379. /**
  380. * Close the existing connection to PEERINFO and reconnect.
  381. *
  382. * @param h handle to the service
  383. */
  384. static void
  385. reconnect (struct GNUNET_PEERINFO_Handle *h)
  386. {
  387. struct GNUNET_MQ_MessageHandler handlers[] = {
  388. GNUNET_MQ_hd_var_size (info,
  389. GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
  390. struct InfoMessage,
  391. h),
  392. GNUNET_MQ_hd_fixed_size (end_iteration,
  393. GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
  394. struct GNUNET_MessageHeader,
  395. h),
  396. GNUNET_MQ_handler_end ()
  397. };
  398. if (NULL != h->r_task)
  399. {
  400. GNUNET_SCHEDULER_cancel (h->r_task);
  401. h->r_task = NULL;
  402. }
  403. if (NULL != h->mq)
  404. {
  405. GNUNET_MQ_destroy (h->mq);
  406. h->mq = NULL;
  407. }
  408. h->mq = GNUNET_CLIENT_connect (h->cfg,
  409. "peerinfo",
  410. handlers,
  411. &mq_error_handler,
  412. h);
  413. if (NULL != h->ic_head)
  414. send_ic_request (h);
  415. }
  416. /**
  417. * Call a method for each known matching host. The callback method
  418. * will be invoked once for each matching host and then finally once
  419. * with a NULL pointer. After that final invocation, the iterator
  420. * context must no longer be used.
  421. *
  422. * Instead of calling this function with `peer == NULL` it is often
  423. * better to use #GNUNET_PEERINFO_notify().
  424. *
  425. * @param h handle to the peerinfo service
  426. * @param include_friend_only include HELLO messages for friends only
  427. * @param peer restrict iteration to this peer only (can be NULL)
  428. * @param callback the method to call for each peer
  429. * @param callback_cls closure for @a callback
  430. * @return iterator context
  431. */
  432. struct GNUNET_PEERINFO_IteratorContext *
  433. GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
  434. int include_friend_only,
  435. const struct GNUNET_PeerIdentity *peer,
  436. GNUNET_PEERINFO_Processor callback,
  437. void *callback_cls)
  438. {
  439. struct GNUNET_PEERINFO_IteratorContext *ic;
  440. ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
  441. ic->h = h;
  442. ic->include_friend_only = include_friend_only;
  443. ic->callback = callback;
  444. ic->callback_cls = callback_cls;
  445. if (NULL != peer)
  446. {
  447. ic->have_peer = GNUNET_YES;
  448. ic->peer = *peer;
  449. }
  450. GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
  451. h->ic_tail,
  452. ic);
  453. if (h->ic_head == ic)
  454. send_ic_request (h);
  455. return ic;
  456. }
  457. /**
  458. * Cancel an iteration over peer information.
  459. *
  460. * @param ic context of the iterator to cancel
  461. */
  462. void
  463. GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
  464. {
  465. struct GNUNET_PEERINFO_Handle *h = ic->h;
  466. ic->callback = NULL;
  467. if (ic == h->ic_head)
  468. return;
  469. GNUNET_CONTAINER_DLL_remove (h->ic_head,
  470. h->ic_tail,
  471. ic);
  472. GNUNET_free (ic);
  473. }
  474. /**
  475. * Add a host to the persistent list. This method operates in
  476. * semi-reliable mode: if the transmission is not completed by
  477. * the time #GNUNET_PEERINFO_disconnect() is called, it will be
  478. * aborted. Furthermore, if a second HELLO is added for the
  479. * same peer before the first one was transmitted, PEERINFO may
  480. * merge the two HELLOs prior to transmission to the service.
  481. *
  482. * @param h handle to the peerinfo service
  483. * @param hello the verified (!) HELLO message
  484. * @param cont continuation to call when done, NULL is allowed
  485. * @param cont_cls closure for @a cont
  486. * @return handle to cancel add operation; all pending
  487. * 'add' operations will be cancelled automatically
  488. * on disconnect, so it is not necessary to keep this
  489. * handle (unless @a cont is NULL and at some point
  490. * calling @a cont must be prevented)
  491. */
  492. struct GNUNET_MQ_Envelope *
  493. GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
  494. const struct GNUNET_HELLO_Message *hello,
  495. GNUNET_SCHEDULER_TaskCallback cont,
  496. void *cont_cls)
  497. {
  498. struct GNUNET_MQ_Envelope *env;
  499. struct GNUNET_PeerIdentity peer;
  500. if (NULL == h->mq)
  501. return NULL;
  502. GNUNET_assert (GNUNET_OK ==
  503. GNUNET_HELLO_get_id (hello,
  504. &peer));
  505. LOG (GNUNET_ERROR_TYPE_DEBUG,
  506. "Adding peer `%s' to PEERINFO database\n",
  507. GNUNET_i2s (&peer));
  508. env = GNUNET_MQ_msg_copy ((const struct GNUNET_MessageHeader *) hello);
  509. if (NULL != cont)
  510. GNUNET_MQ_notify_sent (env,
  511. cont,
  512. cont_cls);
  513. GNUNET_MQ_send (h->mq,
  514. env);
  515. return env;
  516. }
  517. /* end of peerinfo_api.c */