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