aboutsummaryrefslogtreecommitdiff
path: root/src/core/core_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/core_api.c')
-rw-r--r--src/core/core_api.c773
1 files changed, 0 insertions, 773 deletions
diff --git a/src/core/core_api.c b/src/core/core_api.c
deleted file mode 100644
index 81118693d..000000000
--- a/src/core/core_api.c
+++ /dev/null
@@ -1,773 +0,0 @@
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 * @param tc task context
162 */
163static void
164reconnect_task (void *cls)
165{
166 struct GNUNET_CORE_Handle *h = cls;
167
168 h->reconnect_task = NULL;
169 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n");
170 reconnect (h);
171}
172
173
174/**
175 * Notify clients about disconnect and free the entry for connected
176 * peer.
177 *
178 * @param cls the `struct GNUNET_CORE_Handle *`
179 * @param key the peer identity (not used)
180 * @param value the `struct PeerRecord` to free.
181 * @return #GNUNET_YES (continue)
182 */
183static int
184disconnect_and_free_peer_entry (void *cls,
185 const struct GNUNET_PeerIdentity *key,
186 void *value)
187{
188 struct GNUNET_CORE_Handle *h = cls;
189 struct PeerRecord *pr = value;
190
191 GNUNET_assert (pr->h == h);
192 if (NULL != h->disconnects)
193 h->disconnects (h->cls, &pr->peer, pr->client_cls);
194 GNUNET_assert (GNUNET_YES ==
195 GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr));
196 GNUNET_MQ_destroy (pr->mq);
197 GNUNET_assert (NULL == pr->mq);
198 if (NULL != pr->env)
199 {
200 GNUNET_MQ_discard (pr->env);
201 pr->env = NULL;
202 }
203 GNUNET_free (pr);
204 return GNUNET_YES;
205}
206
207
208/**
209 * Close down any existing connection to the CORE service and
210 * try re-establishing it later.
211 *
212 * @param h our handle
213 */
214static void
215reconnect_later (struct GNUNET_CORE_Handle *h)
216{
217 GNUNET_assert (NULL == h->reconnect_task);
218 if (NULL != h->mq)
219 {
220 GNUNET_MQ_destroy (h->mq);
221 h->mq = NULL;
222 }
223 GNUNET_assert (NULL == h->reconnect_task);
224 h->reconnect_task =
225 GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h);
226 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
227 &disconnect_and_free_peer_entry,
228 h);
229 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
230}
231
232
233/**
234 * Error handler for the message queue to the CORE service.
235 * On errors, we reconnect.
236 *
237 * @param cls closure, a `struct GNUNET_CORE_Handle *`
238 * @param error error code
239 */
240static void
241handle_mq_error (void *cls, enum GNUNET_MQ_Error error)
242{
243 struct GNUNET_CORE_Handle *h = cls;
244
245 LOG (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %d\n", error);
246 reconnect_later (h);
247}
248
249
250/**
251 * Implement sending functionality of a message queue for
252 * us sending messages to a peer.
253 *
254 * @param mq the message queue
255 * @param msg the message to send
256 * @param impl_state state of the implementation
257 */
258static void
259core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
260 const struct GNUNET_MessageHeader *msg,
261 void *impl_state)
262{
263 struct PeerRecord *pr = impl_state;
264 struct GNUNET_CORE_Handle *h = pr->h;
265 struct SendMessageRequest *smr;
266 struct SendMessage *sm;
267 struct GNUNET_MQ_Envelope *env;
268 uint16_t msize;
269 enum GNUNET_MQ_PriorityPreferences flags;
270
271 if (NULL == h->mq)
272 {
273 /* We're currently reconnecting, pretend this worked */
274 GNUNET_MQ_impl_send_continue (mq);
275 return;
276 }
277 GNUNET_assert (NULL == pr->env);
278 /* extract options from envelope */
279 env = GNUNET_MQ_get_current_envelope (mq);
280 flags = GNUNET_MQ_env_get_options (env);
281
282 /* check message size for sanity */
283 msize = ntohs (msg->size);
284 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct SendMessage))
285 {
286 GNUNET_break (0);
287 GNUNET_MQ_impl_send_continue (mq);
288 return;
289 }
290
291 /* ask core for transmission */
292 LOG (GNUNET_ERROR_TYPE_DEBUG,
293 "Asking core for transmission of %u bytes to `%s'\n",
294 (unsigned int) msize,
295 GNUNET_i2s (&pr->peer));
296 env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
297 smr->priority = htonl ((uint32_t) flags);
298 smr->peer = pr->peer;
299 smr->size = htons (msize);
300 smr->smr_id = htons (++pr->smr_id_gen);
301 GNUNET_MQ_send (h->mq, env);
302
303 /* prepare message with actual transmission data */
304 pr->env = GNUNET_MQ_msg_nested_mh (sm, GNUNET_MESSAGE_TYPE_CORE_SEND, msg);
305 sm->priority = htonl ((uint32_t) flags);
306 sm->peer = pr->peer;
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "Calling get_message with buffer of %u bytes\n",
309 (unsigned int) msize);
310}
311
312
313/**
314 * Handle destruction of a message queue. Implementations must not
315 * free @a mq, but should take care of @a impl_state.
316 *
317 * @param mq the message queue to destroy
318 * @param impl_state state of the implementation
319 */
320static void
321core_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
322{
323 struct PeerRecord *pr = impl_state;
324
325 GNUNET_assert (mq == pr->mq);
326 pr->mq = NULL;
327}
328
329
330/**
331 * Implementation function that cancels the currently sent message.
332 * Should basically undo whatever #mq_send_impl() did.
333 *
334 * @param mq message queue
335 * @param impl_state state specific to the implementation
336 */
337static void
338core_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
339{
340 struct PeerRecord *pr = impl_state;
341
342 (void) mq;
343 GNUNET_assert (NULL != pr->env);
344 GNUNET_MQ_discard (pr->env);
345 pr->env = NULL;
346}
347
348
349/**
350 * We had an error processing a message we forwarded from a peer to
351 * the CORE service. We should just complain about it but otherwise
352 * continue processing.
353 *
354 * @param cls closure
355 * @param error error code
356 */
357static void
358core_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
359{
360 /* struct PeerRecord *pr = cls; */
361 (void) cls;
362 (void) error;
363 GNUNET_break_op (0);
364}
365
366
367/**
368 * Add the given peer to the list of our connected peers
369 * and create the respective data structures and notify
370 * the application.
371 *
372 * @param h the core handle
373 * @param peer the peer that is connecting to us
374 */
375static void
376connect_peer (struct GNUNET_CORE_Handle *h,
377 const struct GNUNET_PeerIdentity *peer)
378{
379 struct PeerRecord *pr;
380
381 pr = GNUNET_new (struct PeerRecord);
382 pr->peer = *peer;
383 pr->h = h;
384 GNUNET_assert (GNUNET_YES ==
385 GNUNET_CONTAINER_multipeermap_put (
386 h->peers,
387 &pr->peer,
388 pr,
389 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
390 pr->mq = GNUNET_MQ_queue_for_callbacks (&core_mq_send_impl,
391 &core_mq_destroy_impl,
392 &core_mq_cancel_impl,
393 pr,
394 h->handlers,
395 &core_mq_error_handler,
396 pr);
397 if (NULL != h->connects)
398 {
399 pr->client_cls = h->connects (h->cls, &pr->peer, pr->mq);
400 GNUNET_MQ_set_handlers_closure (pr->mq, pr->client_cls);
401 }
402}
403
404
405/**
406 * Handle init reply message received from CORE service. Notify
407 * application that we are now connected to the CORE. Also fake
408 * loopback connection.
409 *
410 * @param cls the `struct GNUNET_CORE_Handle`
411 * @param m the init reply
412 */
413static void
414handle_init_reply (void *cls, const struct InitReplyMessage *m)
415{
416 struct GNUNET_CORE_Handle *h = cls;
417 GNUNET_CORE_StartupCallback init;
418
419 GNUNET_break (0 == ntohl (m->reserved));
420 h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
421 if (NULL != (init = h->init))
422 {
423 /* mark so we don't call init on reconnect */
424 h->init = NULL;
425 h->me = m->my_identity;
426 LOG (GNUNET_ERROR_TYPE_DEBUG,
427 "Connected to core service of peer `%s'.\n",
428 GNUNET_i2s (&h->me));
429 h->have_init = GNUNET_YES;
430 init (h->cls, &h->me);
431 }
432 else
433 {
434 LOG (GNUNET_ERROR_TYPE_DEBUG,
435 "Successfully reconnected to core service.\n");
436 if (GNUNET_NO == h->have_init)
437 {
438 h->me = m->my_identity;
439 h->have_init = GNUNET_YES;
440 }
441 else
442 {
443 GNUNET_break (0 == memcmp (&h->me,
444 &m->my_identity,
445 sizeof(struct GNUNET_PeerIdentity)));
446 }
447 }
448 /* fake 'connect to self' */
449 connect_peer (h, &h->me);
450}
451
452
453/**
454 * Handle connect message received from CORE service.
455 * Notify the application about the new connection.
456 *
457 * @param cls the `struct GNUNET_CORE_Handle`
458 * @param cnm the connect message
459 */
460static void
461handle_connect_notify (void *cls, const struct ConnectNotifyMessage *cnm)
462{
463 struct GNUNET_CORE_Handle *h = cls;
464 struct PeerRecord *pr;
465
466 LOG (GNUNET_ERROR_TYPE_DEBUG,
467 "Received notification about connection from `%s'.\n",
468 GNUNET_i2s (&cnm->peer));
469 if (0 == memcmp (&h->me, &cnm->peer, sizeof(struct GNUNET_PeerIdentity)))
470 {
471 /* connect to self!? */
472 GNUNET_break (0);
473 return;
474 }
475 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer);
476 if (NULL != pr)
477 {
478 GNUNET_break (0);
479 reconnect_later (h);
480 return;
481 }
482 connect_peer (h, &cnm->peer);
483}
484
485
486/**
487 * Handle disconnect message received from CORE service.
488 * Notify the application about the lost connection.
489 *
490 * @param cls the `struct GNUNET_CORE_Handle`
491 * @param dnm message about the disconnect event
492 */
493static void
494handle_disconnect_notify (void *cls, const struct DisconnectNotifyMessage *dnm)
495{
496 struct GNUNET_CORE_Handle *h = cls;
497 struct PeerRecord *pr;
498
499 if (0 == memcmp (&h->me, &dnm->peer, sizeof(struct GNUNET_PeerIdentity)))
500 {
501 /* disconnect from self!? */
502 GNUNET_break (0);
503 return;
504 }
505 GNUNET_break (0 == ntohl (dnm->reserved));
506 LOG (GNUNET_ERROR_TYPE_DEBUG,
507 "Received notification about disconnect from `%s'.\n",
508 GNUNET_i2s (&dnm->peer));
509 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer);
510 if (NULL == pr)
511 {
512 GNUNET_break (0);
513 reconnect_later (h);
514 return;
515 }
516 disconnect_and_free_peer_entry (h, &pr->peer, pr);
517}
518
519
520/**
521 * Check that message received from CORE service is well-formed.
522 *
523 * @param cls the `struct GNUNET_CORE_Handle`
524 * @param ntm the message we got
525 * @return #GNUNET_OK if the message is well-formed
526 */
527static int
528check_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm)
529{
530 uint16_t msize;
531 const struct GNUNET_MessageHeader *em;
532
533 (void) cls;
534 msize = ntohs (ntm->header.size) - sizeof(struct NotifyTrafficMessage);
535 if (msize < sizeof(struct GNUNET_MessageHeader))
536 {
537 GNUNET_break (0);
538 return GNUNET_SYSERR;
539 }
540 em = (const struct GNUNET_MessageHeader *) &ntm[1];
541 if (msize != ntohs (em->size))
542 {
543 GNUNET_break (0);
544 return GNUNET_SYSERR;
545 }
546 return GNUNET_OK;
547}
548
549
550/**
551 * Handle inbound message received from CORE service. If applicable,
552 * notify the application.
553 *
554 * @param cls the `struct GNUNET_CORE_Handle`
555 * @param ntm the message we got from CORE.
556 */
557static void
558handle_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm)
559{
560 struct GNUNET_CORE_Handle *h = cls;
561 const struct GNUNET_MessageHeader *em;
562 struct PeerRecord *pr;
563
564 LOG (GNUNET_ERROR_TYPE_DEBUG,
565 "Received inbound message from `%s'.\n",
566 GNUNET_i2s (&ntm->peer));
567 em = (const struct GNUNET_MessageHeader *) &ntm[1];
568 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer);
569 if (NULL == pr)
570 {
571 GNUNET_break (0);
572 reconnect_later (h);
573 return;
574 }
575 GNUNET_MQ_inject_message (pr->mq, em);
576}
577
578
579/**
580 * Handle message received from CORE service notifying us that we are
581 * now allowed to send a message to a peer. If that message is still
582 * pending, put it into the queue to be transmitted.
583 *
584 * @param cls the `struct GNUNET_CORE_Handle`
585 * @param smr the message we got
586 */
587static void
588handle_send_ready (void *cls, const struct SendMessageReady *smr)
589{
590 struct GNUNET_CORE_Handle *h = cls;
591 struct PeerRecord *pr;
592
593 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer);
594 if (NULL == pr)
595 {
596 GNUNET_break (0);
597 reconnect_later (h);
598 return;
599 }
600 LOG (GNUNET_ERROR_TYPE_DEBUG,
601 "Received notification about transmission readiness to `%s'.\n",
602 GNUNET_i2s (&smr->peer));
603 if (NULL == pr->env)
604 {
605 /* request must have been cancelled between the original request
606 * and the response from CORE, ignore CORE's readiness */
607 return;
608 }
609 if (ntohs (smr->smr_id) != pr->smr_id_gen)
610 {
611 /* READY message is for expired or cancelled message,
612 * ignore! (we should have already sent another request) */
613 return;
614 }
615
616 /* ok, all good, send message out! */
617 GNUNET_MQ_send (h->mq, pr->env);
618 pr->env = NULL;
619 GNUNET_MQ_impl_send_continue (pr->mq);
620}
621
622
623/**
624 * Our current client connection went down. Clean it up and try to
625 * reconnect!
626 *
627 * @param h our handle to the core service
628 */
629static void
630reconnect (struct GNUNET_CORE_Handle *h)
631{
632 struct GNUNET_MQ_MessageHandler handlers[] =
633 { GNUNET_MQ_hd_fixed_size (init_reply,
634 GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY,
635 struct InitReplyMessage,
636 h),
637 GNUNET_MQ_hd_fixed_size (connect_notify,
638 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT,
639 struct ConnectNotifyMessage,
640 h),
641 GNUNET_MQ_hd_fixed_size (disconnect_notify,
642 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT,
643 struct DisconnectNotifyMessage,
644 h),
645 GNUNET_MQ_hd_var_size (notify_inbound,
646 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND,
647 struct NotifyTrafficMessage,
648 h),
649 GNUNET_MQ_hd_fixed_size (send_ready,
650 GNUNET_MESSAGE_TYPE_CORE_SEND_READY,
651 struct SendMessageReady,
652 h),
653 GNUNET_MQ_handler_end () };
654 struct InitMessage *init;
655 struct GNUNET_MQ_Envelope *env;
656 uint16_t *ts;
657
658 GNUNET_assert (NULL == h->mq);
659 h->mq = GNUNET_CLIENT_connect (h->cfg, "core", handlers, &handle_mq_error, h);
660 if (NULL == h->mq)
661 {
662 reconnect_later (h);
663 return;
664 }
665 env = GNUNET_MQ_msg_extra (init,
666 sizeof(uint16_t) * h->hcnt,
667 GNUNET_MESSAGE_TYPE_CORE_INIT);
668 LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service\n");
669 init->options = htonl (0);
670 ts = (uint16_t *) &init[1];
671 for (unsigned int hpos = 0; hpos < h->hcnt; hpos++)
672 ts[hpos] = htons (h->handlers[hpos].type);
673 GNUNET_MQ_send (h->mq, env);
674}
675
676
677/**
678 * Connect to the core service. Note that the connection may complete
679 * (or fail) asynchronously.
680 *
681 * @param cfg configuration to use
682 * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
683 * @param init callback to call once we have successfully
684 * connected to the core service
685 * @param connects function to call on peer connect, can be NULL
686 * @param disconnects function to call on peer disconnect / timeout, can be NULL
687 * @param handlers callbacks for messages we care about, NULL-terminated
688 * @return handle to the core service (only useful for disconnect until @a init is called);
689 * NULL on error (in this case, init is never called)
690 */
691struct GNUNET_CORE_Handle *
692GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
693 void *cls,
694 GNUNET_CORE_StartupCallback init,
695 GNUNET_CORE_ConnectEventHandler connects,
696 GNUNET_CORE_DisconnectEventHandler disconnects,
697 const struct GNUNET_MQ_MessageHandler *handlers)
698{
699 struct GNUNET_CORE_Handle *h;
700
701 h = GNUNET_new (struct GNUNET_CORE_Handle);
702 h->cfg = cfg;
703 h->cls = cls;
704 h->init = init;
705 h->connects = connects;
706 h->disconnects = disconnects;
707 h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
708 h->handlers = GNUNET_MQ_copy_handlers (handlers);
709 h->hcnt = GNUNET_MQ_count_handlers (handlers);
710 GNUNET_assert (h->hcnt <
711 (GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InitMessage))
712 / sizeof(uint16_t));
713 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n");
714 reconnect (h);
715 if (NULL == h->mq)
716 {
717 GNUNET_CORE_disconnect (h);
718 return NULL;
719 }
720 return h;
721}
722
723
724/**
725 * Disconnect from the core service.
726 *
727 * @param handle connection to core to disconnect
728 */
729void
730GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
731{
732 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n");
733 GNUNET_CONTAINER_multipeermap_iterate (handle->peers,
734 &disconnect_and_free_peer_entry,
735 handle);
736 GNUNET_CONTAINER_multipeermap_destroy (handle->peers);
737 handle->peers = NULL;
738 if (NULL != handle->reconnect_task)
739 {
740 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
741 handle->reconnect_task = NULL;
742 }
743 if (NULL != handle->mq)
744 {
745 GNUNET_MQ_destroy (handle->mq);
746 handle->mq = NULL;
747 }
748 GNUNET_free (handle->handlers);
749 GNUNET_free (handle);
750}
751
752
753/**
754 * Obtain the message queue for a connected peer.
755 *
756 * @param h the core handle
757 * @param pid the identity of the peer to check if it has been connected to us
758 * @return NULL if peer is not connected
759 */
760struct GNUNET_MQ_Handle *
761GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h,
762 const struct GNUNET_PeerIdentity *pid)
763{
764 struct PeerRecord *pr;
765
766 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, pid);
767 if (NULL == pr)
768 return NULL;
769 return pr->mq;
770}
771
772
773/* end of core_api.c */