core_api.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-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 core/core_api.c
  18. * @brief core service; this is the main API for encrypted P2P
  19. * communications
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_core_service.h"
  26. #include "core.h"
  27. #define LOG(kind, ...) GNUNET_log_from (kind, "core-api", __VA_ARGS__)
  28. /**
  29. * Information we track for each peer.
  30. */
  31. struct PeerRecord
  32. {
  33. /**
  34. * Corresponding CORE handle.
  35. */
  36. struct GNUNET_CORE_Handle *h;
  37. /**
  38. * Message queue for the peer.
  39. */
  40. struct GNUNET_MQ_Handle *mq;
  41. /**
  42. * Message we are currently trying to pass to the CORE service
  43. * for this peer (from @e mq).
  44. */
  45. struct GNUNET_MQ_Envelope *env;
  46. /**
  47. * Value the client returned when we connected, used
  48. * as the closure in various places.
  49. */
  50. void *client_cls;
  51. /**
  52. * Peer the record is about.
  53. */
  54. struct GNUNET_PeerIdentity peer;
  55. /**
  56. * SendMessageRequest ID generator for this peer.
  57. */
  58. uint16_t smr_id_gen;
  59. };
  60. /**
  61. * Context for the core service connection.
  62. */
  63. struct GNUNET_CORE_Handle
  64. {
  65. /**
  66. * Configuration we're using.
  67. */
  68. const struct GNUNET_CONFIGURATION_Handle *cfg;
  69. /**
  70. * Closure for the various callbacks.
  71. */
  72. void *cls;
  73. /**
  74. * Function to call once we've handshaked with the core service.
  75. */
  76. GNUNET_CORE_StartupCallback init;
  77. /**
  78. * Function to call whenever we're notified about a peer connecting.
  79. */
  80. GNUNET_CORE_ConnectEventHandler connects;
  81. /**
  82. * Function to call whenever we're notified about a peer disconnecting.
  83. */
  84. GNUNET_CORE_DisconnectEventHandler disconnects;
  85. /**
  86. * Function handlers for messages of particular type.
  87. */
  88. struct GNUNET_MQ_MessageHandler *handlers;
  89. /**
  90. * Our message queue for transmissions to the service.
  91. */
  92. struct GNUNET_MQ_Handle *mq;
  93. /**
  94. * Hash map listing all of the peers that we are currently
  95. * connected to.
  96. */
  97. struct GNUNET_CONTAINER_MultiPeerMap *peers;
  98. /**
  99. * Identity of this peer.
  100. */
  101. struct GNUNET_PeerIdentity me;
  102. /**
  103. * ID of reconnect task (if any).
  104. */
  105. struct GNUNET_SCHEDULER_Task *reconnect_task;
  106. /**
  107. * Current delay we use for re-trying to connect to core.
  108. */
  109. struct GNUNET_TIME_Relative retry_backoff;
  110. /**
  111. * Number of entries in the handlers array.
  112. */
  113. unsigned int hcnt;
  114. /**
  115. * Did we ever get INIT?
  116. */
  117. int have_init;
  118. };
  119. /**
  120. * Our current client connection went down. Clean it up
  121. * and try to reconnect!
  122. *
  123. * @param h our handle to the core service
  124. */
  125. static void
  126. reconnect (struct GNUNET_CORE_Handle *h);
  127. /**
  128. * Task schedule to try to re-connect to core.
  129. *
  130. * @param cls the `struct GNUNET_CORE_Handle`
  131. * @param tc task context
  132. */
  133. static void
  134. reconnect_task (void *cls)
  135. {
  136. struct GNUNET_CORE_Handle *h = cls;
  137. h->reconnect_task = NULL;
  138. LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n");
  139. reconnect (h);
  140. }
  141. /**
  142. * Notify clients about disconnect and free the entry for connected
  143. * peer.
  144. *
  145. * @param cls the `struct GNUNET_CORE_Handle *`
  146. * @param key the peer identity (not used)
  147. * @param value the `struct PeerRecord` to free.
  148. * @return #GNUNET_YES (continue)
  149. */
  150. static int
  151. disconnect_and_free_peer_entry (void *cls,
  152. const struct GNUNET_PeerIdentity *key,
  153. void *value)
  154. {
  155. struct GNUNET_CORE_Handle *h = cls;
  156. struct PeerRecord *pr = value;
  157. GNUNET_assert (pr->h == h);
  158. if (NULL != h->disconnects)
  159. h->disconnects (h->cls, &pr->peer, pr->client_cls);
  160. GNUNET_assert (GNUNET_YES ==
  161. GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr));
  162. GNUNET_MQ_destroy (pr->mq);
  163. GNUNET_assert (NULL == pr->mq);
  164. if (NULL != pr->env)
  165. {
  166. GNUNET_MQ_discard (pr->env);
  167. pr->env = NULL;
  168. }
  169. GNUNET_free (pr);
  170. return GNUNET_YES;
  171. }
  172. /**
  173. * Close down any existing connection to the CORE service and
  174. * try re-establishing it later.
  175. *
  176. * @param h our handle
  177. */
  178. static void
  179. reconnect_later (struct GNUNET_CORE_Handle *h)
  180. {
  181. GNUNET_assert (NULL == h->reconnect_task);
  182. if (NULL != h->mq)
  183. {
  184. GNUNET_MQ_destroy (h->mq);
  185. h->mq = NULL;
  186. }
  187. GNUNET_assert (NULL == h->reconnect_task);
  188. h->reconnect_task =
  189. GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h);
  190. GNUNET_CONTAINER_multipeermap_iterate (h->peers,
  191. &disconnect_and_free_peer_entry,
  192. h);
  193. h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
  194. }
  195. /**
  196. * Error handler for the message queue to the CORE service.
  197. * On errors, we reconnect.
  198. *
  199. * @param cls closure, a `struct GNUNET_CORE_Handle *`
  200. * @param error error code
  201. */
  202. static void
  203. handle_mq_error (void *cls, enum GNUNET_MQ_Error error)
  204. {
  205. struct GNUNET_CORE_Handle *h = cls;
  206. LOG (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %d\n", error);
  207. reconnect_later (h);
  208. }
  209. /**
  210. * Implement sending functionality of a message queue for
  211. * us sending messages to a peer.
  212. *
  213. * @param mq the message queue
  214. * @param msg the message to send
  215. * @param impl_state state of the implementation
  216. */
  217. static void
  218. core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
  219. const struct GNUNET_MessageHeader *msg,
  220. void *impl_state)
  221. {
  222. struct PeerRecord *pr = impl_state;
  223. struct GNUNET_CORE_Handle *h = pr->h;
  224. struct SendMessageRequest *smr;
  225. struct SendMessage *sm;
  226. struct GNUNET_MQ_Envelope *env;
  227. uint16_t msize;
  228. enum GNUNET_MQ_PriorityPreferences flags;
  229. if (NULL == h->mq)
  230. {
  231. /* We're currently reconnecting, pretend this worked */
  232. GNUNET_MQ_impl_send_continue (mq);
  233. return;
  234. }
  235. GNUNET_assert (NULL == pr->env);
  236. /* extract options from envelope */
  237. env = GNUNET_MQ_get_current_envelope (mq);
  238. flags = GNUNET_MQ_env_get_options (env);
  239. /* check message size for sanity */
  240. msize = ntohs (msg->size);
  241. if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct SendMessage))
  242. {
  243. GNUNET_break (0);
  244. GNUNET_MQ_impl_send_continue (mq);
  245. return;
  246. }
  247. /* ask core for transmission */
  248. LOG (GNUNET_ERROR_TYPE_DEBUG,
  249. "Asking core for transmission of %u bytes to `%s'\n",
  250. (unsigned int) msize,
  251. GNUNET_i2s (&pr->peer));
  252. env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
  253. smr->priority = htonl ((uint32_t) flags);
  254. smr->peer = pr->peer;
  255. smr->size = htons (msize);
  256. smr->smr_id = htons (++pr->smr_id_gen);
  257. GNUNET_MQ_send (h->mq, env);
  258. /* prepare message with actual transmission data */
  259. pr->env = GNUNET_MQ_msg_nested_mh (sm, GNUNET_MESSAGE_TYPE_CORE_SEND, msg);
  260. sm->priority = htonl ((uint32_t) flags);
  261. sm->peer = pr->peer;
  262. LOG (GNUNET_ERROR_TYPE_DEBUG,
  263. "Calling get_message with buffer of %u bytes\n",
  264. (unsigned int) msize);
  265. }
  266. /**
  267. * Handle destruction of a message queue. Implementations must not
  268. * free @a mq, but should take care of @a impl_state.
  269. *
  270. * @param mq the message queue to destroy
  271. * @param impl_state state of the implementation
  272. */
  273. static void
  274. core_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
  275. {
  276. struct PeerRecord *pr = impl_state;
  277. GNUNET_assert (mq == pr->mq);
  278. pr->mq = NULL;
  279. }
  280. /**
  281. * Implementation function that cancels the currently sent message.
  282. * Should basically undo whatever #mq_send_impl() did.
  283. *
  284. * @param mq message queue
  285. * @param impl_state state specific to the implementation
  286. */
  287. static void
  288. core_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
  289. {
  290. struct PeerRecord *pr = impl_state;
  291. (void) mq;
  292. GNUNET_assert (NULL != pr->env);
  293. GNUNET_MQ_discard (pr->env);
  294. pr->env = NULL;
  295. }
  296. /**
  297. * We had an error processing a message we forwarded from a peer to
  298. * the CORE service. We should just complain about it but otherwise
  299. * continue processing.
  300. *
  301. * @param cls closure
  302. * @param error error code
  303. */
  304. static void
  305. core_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
  306. {
  307. /* struct PeerRecord *pr = cls; */
  308. (void) cls;
  309. (void) error;
  310. GNUNET_break_op (0);
  311. }
  312. /**
  313. * Add the given peer to the list of our connected peers
  314. * and create the respective data structures and notify
  315. * the application.
  316. *
  317. * @param h the core handle
  318. * @param peer the peer that is connecting to us
  319. */
  320. static void
  321. connect_peer (struct GNUNET_CORE_Handle *h,
  322. const struct GNUNET_PeerIdentity *peer)
  323. {
  324. struct PeerRecord *pr;
  325. pr = GNUNET_new (struct PeerRecord);
  326. pr->peer = *peer;
  327. pr->h = h;
  328. GNUNET_assert (GNUNET_YES ==
  329. GNUNET_CONTAINER_multipeermap_put (
  330. h->peers,
  331. &pr->peer,
  332. pr,
  333. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  334. pr->mq = GNUNET_MQ_queue_for_callbacks (&core_mq_send_impl,
  335. &core_mq_destroy_impl,
  336. &core_mq_cancel_impl,
  337. pr,
  338. h->handlers,
  339. &core_mq_error_handler,
  340. pr);
  341. if (NULL != h->connects)
  342. {
  343. pr->client_cls = h->connects (h->cls, &pr->peer, pr->mq);
  344. GNUNET_MQ_set_handlers_closure (pr->mq, pr->client_cls);
  345. }
  346. }
  347. /**
  348. * Handle init reply message received from CORE service. Notify
  349. * application that we are now connected to the CORE. Also fake
  350. * loopback connection.
  351. *
  352. * @param cls the `struct GNUNET_CORE_Handle`
  353. * @param m the init reply
  354. */
  355. static void
  356. handle_init_reply (void *cls, const struct InitReplyMessage *m)
  357. {
  358. struct GNUNET_CORE_Handle *h = cls;
  359. GNUNET_CORE_StartupCallback init;
  360. GNUNET_break (0 == ntohl (m->reserved));
  361. h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
  362. if (NULL != (init = h->init))
  363. {
  364. /* mark so we don't call init on reconnect */
  365. h->init = NULL;
  366. h->me = m->my_identity;
  367. LOG (GNUNET_ERROR_TYPE_DEBUG,
  368. "Connected to core service of peer `%s'.\n",
  369. GNUNET_i2s (&h->me));
  370. h->have_init = GNUNET_YES;
  371. init (h->cls, &h->me);
  372. }
  373. else
  374. {
  375. LOG (GNUNET_ERROR_TYPE_DEBUG,
  376. "Successfully reconnected to core service.\n");
  377. if (GNUNET_NO == h->have_init)
  378. {
  379. h->me = m->my_identity;
  380. h->have_init = GNUNET_YES;
  381. }
  382. else
  383. {
  384. GNUNET_break (0 == memcmp (&h->me,
  385. &m->my_identity,
  386. sizeof(struct GNUNET_PeerIdentity)));
  387. }
  388. }
  389. /* fake 'connect to self' */
  390. connect_peer (h, &h->me);
  391. }
  392. /**
  393. * Handle connect message received from CORE service.
  394. * Notify the application about the new connection.
  395. *
  396. * @param cls the `struct GNUNET_CORE_Handle`
  397. * @param cnm the connect message
  398. */
  399. static void
  400. handle_connect_notify (void *cls, const struct ConnectNotifyMessage *cnm)
  401. {
  402. struct GNUNET_CORE_Handle *h = cls;
  403. struct PeerRecord *pr;
  404. LOG (GNUNET_ERROR_TYPE_DEBUG,
  405. "Received notification about connection from `%s'.\n",
  406. GNUNET_i2s (&cnm->peer));
  407. if (0 == memcmp (&h->me, &cnm->peer, sizeof(struct GNUNET_PeerIdentity)))
  408. {
  409. /* connect to self!? */
  410. GNUNET_break (0);
  411. return;
  412. }
  413. pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer);
  414. if (NULL != pr)
  415. {
  416. GNUNET_break (0);
  417. reconnect_later (h);
  418. return;
  419. }
  420. connect_peer (h, &cnm->peer);
  421. }
  422. /**
  423. * Handle disconnect message received from CORE service.
  424. * Notify the application about the lost connection.
  425. *
  426. * @param cls the `struct GNUNET_CORE_Handle`
  427. * @param dnm message about the disconnect event
  428. */
  429. static void
  430. handle_disconnect_notify (void *cls, const struct DisconnectNotifyMessage *dnm)
  431. {
  432. struct GNUNET_CORE_Handle *h = cls;
  433. struct PeerRecord *pr;
  434. if (0 == memcmp (&h->me, &dnm->peer, sizeof(struct GNUNET_PeerIdentity)))
  435. {
  436. /* disconnect from self!? */
  437. GNUNET_break (0);
  438. return;
  439. }
  440. GNUNET_break (0 == ntohl (dnm->reserved));
  441. LOG (GNUNET_ERROR_TYPE_DEBUG,
  442. "Received notification about disconnect from `%s'.\n",
  443. GNUNET_i2s (&dnm->peer));
  444. pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer);
  445. if (NULL == pr)
  446. {
  447. GNUNET_break (0);
  448. reconnect_later (h);
  449. return;
  450. }
  451. disconnect_and_free_peer_entry (h, &pr->peer, pr);
  452. }
  453. /**
  454. * Check that message received from CORE service is well-formed.
  455. *
  456. * @param cls the `struct GNUNET_CORE_Handle`
  457. * @param ntm the message we got
  458. * @return #GNUNET_OK if the message is well-formed
  459. */
  460. static int
  461. check_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm)
  462. {
  463. uint16_t msize;
  464. const struct GNUNET_MessageHeader *em;
  465. (void) cls;
  466. msize = ntohs (ntm->header.size) - sizeof(struct NotifyTrafficMessage);
  467. if (msize < sizeof(struct GNUNET_MessageHeader))
  468. {
  469. GNUNET_break (0);
  470. return GNUNET_SYSERR;
  471. }
  472. em = (const struct GNUNET_MessageHeader *) &ntm[1];
  473. if (msize != ntohs (em->size))
  474. {
  475. GNUNET_break (0);
  476. return GNUNET_SYSERR;
  477. }
  478. return GNUNET_OK;
  479. }
  480. /**
  481. * Handle inbound message received from CORE service. If applicable,
  482. * notify the application.
  483. *
  484. * @param cls the `struct GNUNET_CORE_Handle`
  485. * @param ntm the message we got from CORE.
  486. */
  487. static void
  488. handle_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm)
  489. {
  490. struct GNUNET_CORE_Handle *h = cls;
  491. const struct GNUNET_MessageHeader *em;
  492. struct PeerRecord *pr;
  493. LOG (GNUNET_ERROR_TYPE_DEBUG,
  494. "Received inbound message from `%s'.\n",
  495. GNUNET_i2s (&ntm->peer));
  496. em = (const struct GNUNET_MessageHeader *) &ntm[1];
  497. pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer);
  498. if (NULL == pr)
  499. {
  500. GNUNET_break (0);
  501. reconnect_later (h);
  502. return;
  503. }
  504. GNUNET_MQ_inject_message (pr->mq, em);
  505. }
  506. /**
  507. * Handle message received from CORE service notifying us that we are
  508. * now allowed to send a message to a peer. If that message is still
  509. * pending, put it into the queue to be transmitted.
  510. *
  511. * @param cls the `struct GNUNET_CORE_Handle`
  512. * @param smr the message we got
  513. */
  514. static void
  515. handle_send_ready (void *cls, const struct SendMessageReady *smr)
  516. {
  517. struct GNUNET_CORE_Handle *h = cls;
  518. struct PeerRecord *pr;
  519. pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer);
  520. if (NULL == pr)
  521. {
  522. GNUNET_break (0);
  523. reconnect_later (h);
  524. return;
  525. }
  526. LOG (GNUNET_ERROR_TYPE_DEBUG,
  527. "Received notification about transmission readiness to `%s'.\n",
  528. GNUNET_i2s (&smr->peer));
  529. if (NULL == pr->env)
  530. {
  531. /* request must have been cancelled between the original request
  532. * and the response from CORE, ignore CORE's readiness */
  533. return;
  534. }
  535. if (ntohs (smr->smr_id) != pr->smr_id_gen)
  536. {
  537. /* READY message is for expired or cancelled message,
  538. * ignore! (we should have already sent another request) */
  539. return;
  540. }
  541. /* ok, all good, send message out! */
  542. GNUNET_MQ_send (h->mq, pr->env);
  543. pr->env = NULL;
  544. GNUNET_MQ_impl_send_continue (pr->mq);
  545. }
  546. /**
  547. * Our current client connection went down. Clean it up and try to
  548. * reconnect!
  549. *
  550. * @param h our handle to the core service
  551. */
  552. static void
  553. reconnect (struct GNUNET_CORE_Handle *h)
  554. {
  555. struct GNUNET_MQ_MessageHandler handlers[] =
  556. { GNUNET_MQ_hd_fixed_size (init_reply,
  557. GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY,
  558. struct InitReplyMessage,
  559. h),
  560. GNUNET_MQ_hd_fixed_size (connect_notify,
  561. GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT,
  562. struct ConnectNotifyMessage,
  563. h),
  564. GNUNET_MQ_hd_fixed_size (disconnect_notify,
  565. GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT,
  566. struct DisconnectNotifyMessage,
  567. h),
  568. GNUNET_MQ_hd_var_size (notify_inbound,
  569. GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND,
  570. struct NotifyTrafficMessage,
  571. h),
  572. GNUNET_MQ_hd_fixed_size (send_ready,
  573. GNUNET_MESSAGE_TYPE_CORE_SEND_READY,
  574. struct SendMessageReady,
  575. h),
  576. GNUNET_MQ_handler_end () };
  577. struct InitMessage *init;
  578. struct GNUNET_MQ_Envelope *env;
  579. uint16_t *ts;
  580. GNUNET_assert (NULL == h->mq);
  581. h->mq = GNUNET_CLIENT_connect (h->cfg, "core", handlers, &handle_mq_error, h);
  582. if (NULL == h->mq)
  583. {
  584. reconnect_later (h);
  585. return;
  586. }
  587. env = GNUNET_MQ_msg_extra (init,
  588. sizeof(uint16_t) * h->hcnt,
  589. GNUNET_MESSAGE_TYPE_CORE_INIT);
  590. LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service\n");
  591. init->options = htonl (0);
  592. ts = (uint16_t *) &init[1];
  593. for (unsigned int hpos = 0; hpos < h->hcnt; hpos++)
  594. ts[hpos] = htons (h->handlers[hpos].type);
  595. GNUNET_MQ_send (h->mq, env);
  596. }
  597. /**
  598. * Connect to the core service. Note that the connection may complete
  599. * (or fail) asynchronously.
  600. *
  601. * @param cfg configuration to use
  602. * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
  603. * @param init callback to call once we have successfully
  604. * connected to the core service
  605. * @param connects function to call on peer connect, can be NULL
  606. * @param disconnects function to call on peer disconnect / timeout, can be NULL
  607. * @param handlers callbacks for messages we care about, NULL-terminated
  608. * @return handle to the core service (only useful for disconnect until @a init is called);
  609. * NULL on error (in this case, init is never called)
  610. */
  611. struct GNUNET_CORE_Handle *
  612. GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
  613. void *cls,
  614. GNUNET_CORE_StartupCallback init,
  615. GNUNET_CORE_ConnectEventHandler connects,
  616. GNUNET_CORE_DisconnectEventHandler disconnects,
  617. const struct GNUNET_MQ_MessageHandler *handlers)
  618. {
  619. struct GNUNET_CORE_Handle *h;
  620. h = GNUNET_new (struct GNUNET_CORE_Handle);
  621. h->cfg = cfg;
  622. h->cls = cls;
  623. h->init = init;
  624. h->connects = connects;
  625. h->disconnects = disconnects;
  626. h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
  627. h->handlers = GNUNET_MQ_copy_handlers (handlers);
  628. h->hcnt = GNUNET_MQ_count_handlers (handlers);
  629. GNUNET_assert (h->hcnt <
  630. (GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InitMessage))
  631. / sizeof(uint16_t));
  632. LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n");
  633. reconnect (h);
  634. if (NULL == h->mq)
  635. {
  636. GNUNET_CORE_disconnect (h);
  637. return NULL;
  638. }
  639. return h;
  640. }
  641. /**
  642. * Disconnect from the core service.
  643. *
  644. * @param handle connection to core to disconnect
  645. */
  646. void
  647. GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
  648. {
  649. LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n");
  650. GNUNET_CONTAINER_multipeermap_iterate (handle->peers,
  651. &disconnect_and_free_peer_entry,
  652. handle);
  653. GNUNET_CONTAINER_multipeermap_destroy (handle->peers);
  654. handle->peers = NULL;
  655. if (NULL != handle->reconnect_task)
  656. {
  657. GNUNET_SCHEDULER_cancel (handle->reconnect_task);
  658. handle->reconnect_task = NULL;
  659. }
  660. if (NULL != handle->mq)
  661. {
  662. GNUNET_MQ_destroy (handle->mq);
  663. handle->mq = NULL;
  664. }
  665. GNUNET_free (handle->handlers);
  666. GNUNET_free (handle);
  667. }
  668. /**
  669. * Obtain the message queue for a connected peer.
  670. *
  671. * @param h the core handle
  672. * @param pid the identity of the peer to check if it has been connected to us
  673. * @return NULL if peer is not connected
  674. */
  675. struct GNUNET_MQ_Handle *
  676. GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h,
  677. const struct GNUNET_PeerIdentity *pid)
  678. {
  679. struct PeerRecord *pr;
  680. pr = GNUNET_CONTAINER_multipeermap_get (h->peers, pid);
  681. if (NULL == pr)
  682. return NULL;
  683. return pr->mq;
  684. }
  685. /* end of core_api.c */