diff options
Diffstat (limited to 'src/cadet/cadet_api.c')
-rw-r--r-- | src/cadet/cadet_api.c | 1706 |
1 files changed, 1706 insertions, 0 deletions
diff --git a/src/cadet/cadet_api.c b/src/cadet/cadet_api.c new file mode 100644 index 000000000..c9f2a11bb --- /dev/null +++ b/src/cadet/cadet_api.c | |||
@@ -0,0 +1,1706 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | 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 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file cadet/cadet_api.c | ||
22 | * @brief cadet api: client implementation of cadet service | ||
23 | * @author Bartlomiej Polot | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_cadet_service.h" | ||
30 | #include "cadet.h" | ||
31 | #include "cadet_protocol.h" | ||
32 | |||
33 | #define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__) | ||
34 | |||
35 | /** | ||
36 | * Ugly legacy hack. | ||
37 | */ | ||
38 | union CadetInfoCB | ||
39 | { | ||
40 | |||
41 | /** | ||
42 | * Channel callback. | ||
43 | */ | ||
44 | GNUNET_CADET_ChannelCB channel_cb; | ||
45 | |||
46 | /** | ||
47 | * Monitor callback | ||
48 | */ | ||
49 | GNUNET_CADET_PeersCB peers_cb; | ||
50 | |||
51 | /** | ||
52 | * Monitor callback | ||
53 | */ | ||
54 | GNUNET_CADET_PeerCB peer_cb; | ||
55 | |||
56 | /** | ||
57 | * Monitor callback | ||
58 | */ | ||
59 | GNUNET_CADET_TunnelsCB tunnels_cb; | ||
60 | |||
61 | /** | ||
62 | * Tunnel callback. | ||
63 | */ | ||
64 | GNUNET_CADET_TunnelCB tunnel_cb; | ||
65 | }; | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Opaque handle to the service. | ||
70 | */ | ||
71 | struct GNUNET_CADET_Handle | ||
72 | { | ||
73 | /** | ||
74 | * Message queue. | ||
75 | */ | ||
76 | struct GNUNET_MQ_Handle *mq; | ||
77 | |||
78 | /** | ||
79 | * Ports open. | ||
80 | */ | ||
81 | struct GNUNET_CONTAINER_MultiHashMap *ports; | ||
82 | |||
83 | /** | ||
84 | * Channels open. | ||
85 | */ | ||
86 | struct GNUNET_CONTAINER_MultiHashMap32 *channels; | ||
87 | |||
88 | /** | ||
89 | * child of the next channel to create (to avoid reusing IDs often) | ||
90 | */ | ||
91 | struct GNUNET_CADET_ClientChannelNumber next_ccn; | ||
92 | |||
93 | /** | ||
94 | * Configuration given by the client, in case of reconnection | ||
95 | */ | ||
96 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
97 | |||
98 | /** | ||
99 | * Task for trying to reconnect. | ||
100 | */ | ||
101 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
102 | |||
103 | /** | ||
104 | * Callback for an info task (only one active at a time). | ||
105 | */ | ||
106 | union CadetInfoCB info_cb; | ||
107 | |||
108 | /** | ||
109 | * Info callback closure for @c info_cb. | ||
110 | */ | ||
111 | void *info_cls; | ||
112 | |||
113 | /** | ||
114 | * Time to the next reconnect in case one reconnect fails | ||
115 | */ | ||
116 | struct GNUNET_TIME_Relative reconnect_time; | ||
117 | |||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Opaque handle to a channel. | ||
123 | */ | ||
124 | struct GNUNET_CADET_Channel | ||
125 | { | ||
126 | |||
127 | /** | ||
128 | * Other end of the channel. | ||
129 | */ | ||
130 | struct GNUNET_PeerIdentity peer; | ||
131 | |||
132 | /** | ||
133 | * Handle to the cadet this channel belongs to | ||
134 | */ | ||
135 | struct GNUNET_CADET_Handle *cadet; | ||
136 | |||
137 | /** | ||
138 | * Channel's port, if incoming. | ||
139 | */ | ||
140 | struct GNUNET_CADET_Port *incoming_port; | ||
141 | |||
142 | /** | ||
143 | * Any data the caller wants to put in here, used for the | ||
144 | * various callbacks (@e disconnects, @e window_changes, handlers). | ||
145 | */ | ||
146 | void *ctx; | ||
147 | |||
148 | /** | ||
149 | * Message Queue for the channel (which we are implementing). | ||
150 | */ | ||
151 | struct GNUNET_MQ_Handle *mq; | ||
152 | |||
153 | /** | ||
154 | * Task to allow mq to send more traffic. | ||
155 | */ | ||
156 | struct GNUNET_SCHEDULER_Task *mq_cont; | ||
157 | |||
158 | /** | ||
159 | * Pending envelope with a message to be transmitted to the | ||
160 | * service as soon as we are allowed to. Should only be | ||
161 | * non-NULL if @e allow_send is 0. | ||
162 | */ | ||
163 | struct GNUNET_MQ_Envelope *pending_env; | ||
164 | |||
165 | /** | ||
166 | * Window change handler. | ||
167 | */ | ||
168 | GNUNET_CADET_WindowSizeEventHandler window_changes; | ||
169 | |||
170 | /** | ||
171 | * Disconnect handler. | ||
172 | */ | ||
173 | GNUNET_CADET_DisconnectEventHandler disconnects; | ||
174 | |||
175 | /** | ||
176 | * Local ID of the channel, #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI bit is set if outbound. | ||
177 | */ | ||
178 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
179 | |||
180 | /** | ||
181 | * Channel options: reliability, etc. | ||
182 | */ | ||
183 | enum GNUNET_CADET_ChannelOption options; | ||
184 | |||
185 | /** | ||
186 | * How many messages are we allowed to send to the service right now? | ||
187 | */ | ||
188 | unsigned int allow_send; | ||
189 | |||
190 | }; | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Opaque handle to a port. | ||
195 | */ | ||
196 | struct GNUNET_CADET_Port | ||
197 | { | ||
198 | |||
199 | /** | ||
200 | * Port "number" | ||
201 | */ | ||
202 | struct GNUNET_HashCode id; | ||
203 | |||
204 | /** | ||
205 | * Handle to the CADET session this port belongs to. | ||
206 | */ | ||
207 | struct GNUNET_CADET_Handle *cadet; | ||
208 | |||
209 | /** | ||
210 | * Closure for @a handler. | ||
211 | */ | ||
212 | void *cls; | ||
213 | |||
214 | /** | ||
215 | * Handler for incoming channels on this port | ||
216 | */ | ||
217 | GNUNET_CADET_ConnectEventHandler connects; | ||
218 | |||
219 | /** | ||
220 | * Closure for @ref connects | ||
221 | */ | ||
222 | void *connects_cls; | ||
223 | |||
224 | /** | ||
225 | * Window size change handler. | ||
226 | */ | ||
227 | GNUNET_CADET_WindowSizeEventHandler window_changes; | ||
228 | |||
229 | /** | ||
230 | * Handler called when an incoming channel is destroyed. | ||
231 | */ | ||
232 | GNUNET_CADET_DisconnectEventHandler disconnects; | ||
233 | |||
234 | /** | ||
235 | * Payload handlers for incoming channels. | ||
236 | */ | ||
237 | struct GNUNET_MQ_MessageHandler *handlers; | ||
238 | }; | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Find the Port struct for a hash. | ||
243 | * | ||
244 | * @param h CADET handle. | ||
245 | * @param hash HashCode for the port number. | ||
246 | * @return The port handle if known, NULL otherwise. | ||
247 | */ | ||
248 | static struct GNUNET_CADET_Port * | ||
249 | find_port (const struct GNUNET_CADET_Handle *h, | ||
250 | const struct GNUNET_HashCode *hash) | ||
251 | { | ||
252 | return GNUNET_CONTAINER_multihashmap_get (h->ports, | ||
253 | hash); | ||
254 | } | ||
255 | |||
256 | |||
257 | /** | ||
258 | * Get the channel handler for the channel specified by id from the given handle | ||
259 | * | ||
260 | * @param h Cadet handle | ||
261 | * @param ccn ID of the wanted channel | ||
262 | * @return handle to the required channel or NULL if not found | ||
263 | */ | ||
264 | static struct GNUNET_CADET_Channel * | ||
265 | find_channel (struct GNUNET_CADET_Handle *h, | ||
266 | struct GNUNET_CADET_ClientChannelNumber ccn) | ||
267 | { | ||
268 | return GNUNET_CONTAINER_multihashmap32_get (h->channels, | ||
269 | ntohl (ccn.channel_of_client)); | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Create a new channel and insert it in the channel list of the cadet handle | ||
275 | * | ||
276 | * @param h Cadet handle | ||
277 | * @param ccnp pointer to desired ccn of the channel, NULL to assign one automatically. | ||
278 | * @return Handle to the created channel. | ||
279 | */ | ||
280 | static struct GNUNET_CADET_Channel * | ||
281 | create_channel (struct GNUNET_CADET_Handle *h, | ||
282 | const struct GNUNET_CADET_ClientChannelNumber *ccnp) | ||
283 | { | ||
284 | struct GNUNET_CADET_Channel *ch; | ||
285 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
286 | |||
287 | ch = GNUNET_new (struct GNUNET_CADET_Channel); | ||
288 | ch->cadet = h; | ||
289 | if (NULL == ccnp) | ||
290 | { | ||
291 | while (NULL != | ||
292 | find_channel (h, | ||
293 | h->next_ccn)) | ||
294 | h->next_ccn.channel_of_client | ||
295 | = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI | (1 + ntohl (h->next_ccn.channel_of_client))); | ||
296 | ccn = h->next_ccn; | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | ccn = *ccnp; | ||
301 | } | ||
302 | ch->ccn = ccn; | ||
303 | GNUNET_assert (GNUNET_OK == | ||
304 | GNUNET_CONTAINER_multihashmap32_put (h->channels, | ||
305 | ntohl (ch->ccn.channel_of_client), | ||
306 | ch, | ||
307 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
308 | return ch; | ||
309 | } | ||
310 | |||
311 | |||
312 | /** | ||
313 | * Destroy the specified channel. | ||
314 | * - Destroys all peers, calling the disconnect callback on each if needed | ||
315 | * - Cancels all outgoing traffic for that channel, calling respective notifys | ||
316 | * - Calls cleaner if channel was inbound | ||
317 | * - Frees all memory used | ||
318 | * | ||
319 | * @param ch Pointer to the channel. | ||
320 | * @param call_cleaner Whether to call the cleaner handler. | ||
321 | */ | ||
322 | static void | ||
323 | destroy_channel (struct GNUNET_CADET_Channel *ch) | ||
324 | { | ||
325 | struct GNUNET_CADET_Handle *h = ch->cadet; | ||
326 | |||
327 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
328 | "Destroying channel %X of %p\n", | ||
329 | ch->ccn, | ||
330 | h); | ||
331 | GNUNET_assert (GNUNET_YES == | ||
332 | GNUNET_CONTAINER_multihashmap32_remove (h->channels, | ||
333 | ntohl (ch->ccn.channel_of_client), | ||
334 | ch)); | ||
335 | if (NULL != ch->mq_cont) | ||
336 | { | ||
337 | GNUNET_SCHEDULER_cancel (ch->mq_cont); | ||
338 | ch->mq_cont = NULL; | ||
339 | } | ||
340 | /* signal channel destruction */ | ||
341 | if (NULL != ch->disconnects) | ||
342 | ch->disconnects (ch->ctx, | ||
343 | ch); | ||
344 | if (NULL != ch->pending_env) | ||
345 | GNUNET_MQ_discard (ch->pending_env); | ||
346 | GNUNET_MQ_destroy (ch->mq); | ||
347 | GNUNET_free (ch); | ||
348 | } | ||
349 | |||
350 | |||
351 | /** | ||
352 | * Reconnect to the service, retransmit all infomation to try to restore the | ||
353 | * original state. | ||
354 | * | ||
355 | * @param h handle to the cadet | ||
356 | */ | ||
357 | static void | ||
358 | reconnect (struct GNUNET_CADET_Handle *h); | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Reconnect callback: tries to reconnect again after a failer previous | ||
363 | * reconnecttion | ||
364 | * | ||
365 | * @param cls closure (cadet handle) | ||
366 | */ | ||
367 | static void | ||
368 | reconnect_cbk (void *cls) | ||
369 | { | ||
370 | struct GNUNET_CADET_Handle *h = cls; | ||
371 | |||
372 | h->reconnect_task = NULL; | ||
373 | reconnect (h); | ||
374 | } | ||
375 | |||
376 | |||
377 | /** | ||
378 | * Function called during #reconnect() to destroy | ||
379 | * all channels that are still open. | ||
380 | * | ||
381 | * @param cls the `struct GNUNET_CADET_Handle` | ||
382 | * @param cid chanenl ID | ||
383 | * @param value a `struct GNUNET_CADET_Channel` to destroy | ||
384 | * @return #GNUNET_OK (continue to iterate) | ||
385 | */ | ||
386 | static int | ||
387 | destroy_channel_on_reconnect_cb (void *cls, | ||
388 | uint32_t cid, | ||
389 | void *value) | ||
390 | { | ||
391 | /* struct GNUNET_CADET_Handle *handle = cls; */ | ||
392 | struct GNUNET_CADET_Channel *ch = value; | ||
393 | |||
394 | destroy_channel (ch); | ||
395 | return GNUNET_OK; | ||
396 | } | ||
397 | |||
398 | |||
399 | /** | ||
400 | * Reconnect to the service, retransmit all infomation to try to restore the | ||
401 | * original state. | ||
402 | * | ||
403 | * @param h handle to the cadet | ||
404 | * | ||
405 | * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...) | ||
406 | */ | ||
407 | static void | ||
408 | schedule_reconnect (struct GNUNET_CADET_Handle *h) | ||
409 | { | ||
410 | if (NULL != h->reconnect_task) | ||
411 | return; | ||
412 | GNUNET_CONTAINER_multihashmap32_iterate (h->channels, | ||
413 | &destroy_channel_on_reconnect_cb, | ||
414 | h); | ||
415 | h->reconnect_task | ||
416 | = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, | ||
417 | &reconnect_cbk, | ||
418 | h); | ||
419 | h->reconnect_time | ||
420 | = GNUNET_TIME_STD_BACKOFF (h->reconnect_time); | ||
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Notify the application about a change in the window size (if needed). | ||
426 | * | ||
427 | * @param ch Channel to notify about. | ||
428 | */ | ||
429 | static void | ||
430 | notify_window_size (struct GNUNET_CADET_Channel *ch) | ||
431 | { | ||
432 | if (NULL != ch->window_changes) | ||
433 | ch->window_changes (ch->ctx, | ||
434 | ch, /* FIXME: remove 'ch'? */ | ||
435 | ch->allow_send); | ||
436 | } | ||
437 | |||
438 | |||
439 | /** | ||
440 | * Transmit the next message from our queue. | ||
441 | * | ||
442 | * @param cls Closure (channel whose mq to activate). | ||
443 | */ | ||
444 | static void | ||
445 | cadet_mq_send_now (void *cls) | ||
446 | { | ||
447 | struct GNUNET_CADET_Channel *ch = cls; | ||
448 | struct GNUNET_MQ_Envelope *env = ch->pending_env; | ||
449 | |||
450 | ch->mq_cont = NULL; | ||
451 | if (0 == ch->allow_send) | ||
452 | { | ||
453 | /* how did we get here? */ | ||
454 | GNUNET_break (0); | ||
455 | return; | ||
456 | } | ||
457 | if (NULL == env) | ||
458 | { | ||
459 | /* how did we get here? */ | ||
460 | GNUNET_break (0); | ||
461 | return; | ||
462 | } | ||
463 | ch->allow_send--; | ||
464 | ch->pending_env = NULL; | ||
465 | GNUNET_MQ_send (ch->cadet->mq, | ||
466 | env); | ||
467 | GNUNET_MQ_impl_send_continue (ch->mq); | ||
468 | } | ||
469 | |||
470 | |||
471 | /** | ||
472 | * Implement sending functionality of a message queue for | ||
473 | * us sending messages to a peer. | ||
474 | * | ||
475 | * Encapsulates the payload message in a #GNUNET_CADET_LocalData message | ||
476 | * in order to label the message with the channel ID and send the | ||
477 | * encapsulated message to the service. | ||
478 | * | ||
479 | * @param mq the message queue | ||
480 | * @param msg the message to send | ||
481 | * @param impl_state state of the implementation | ||
482 | */ | ||
483 | static void | ||
484 | cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq, | ||
485 | const struct GNUNET_MessageHeader *msg, | ||
486 | void *impl_state) | ||
487 | { | ||
488 | struct GNUNET_CADET_Channel *ch = impl_state; | ||
489 | struct GNUNET_CADET_Handle *h = ch->cadet; | ||
490 | uint16_t msize; | ||
491 | struct GNUNET_MQ_Envelope *env; | ||
492 | struct GNUNET_CADET_LocalData *cadet_msg; | ||
493 | |||
494 | if (NULL == h->mq) | ||
495 | { | ||
496 | /* We're currently reconnecting, pretend this worked */ | ||
497 | GNUNET_MQ_impl_send_continue (mq); | ||
498 | return; | ||
499 | } | ||
500 | |||
501 | /* check message size for sanity */ | ||
502 | msize = ntohs (msg->size); | ||
503 | if (msize > GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE) | ||
504 | { | ||
505 | GNUNET_break (0); | ||
506 | GNUNET_MQ_impl_send_continue (mq); | ||
507 | return; | ||
508 | } | ||
509 | env = GNUNET_MQ_msg_nested_mh (cadet_msg, | ||
510 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, | ||
511 | msg); | ||
512 | cadet_msg->ccn = ch->ccn; | ||
513 | GNUNET_assert (NULL == ch->pending_env); | ||
514 | ch->pending_env = env; | ||
515 | if (0 < ch->allow_send) | ||
516 | ch->mq_cont | ||
517 | = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now, | ||
518 | ch); | ||
519 | } | ||
520 | |||
521 | |||
522 | /** | ||
523 | * Handle destruction of a message queue. Implementations must not | ||
524 | * free @a mq, but should take care of @a impl_state. | ||
525 | * | ||
526 | * @param mq the message queue to destroy | ||
527 | * @param impl_state state of the implementation | ||
528 | */ | ||
529 | static void | ||
530 | cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, | ||
531 | void *impl_state) | ||
532 | { | ||
533 | struct GNUNET_CADET_Channel *ch = impl_state; | ||
534 | |||
535 | GNUNET_assert (mq == ch->mq); | ||
536 | ch->mq = NULL; | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * We had an error processing a message we forwarded from a peer to | ||
542 | * the CADET service. We should just complain about it but otherwise | ||
543 | * continue processing. | ||
544 | * | ||
545 | * @param cls closure with our `struct GNUNET_CADET_Channel` | ||
546 | * @param error error code | ||
547 | */ | ||
548 | static void | ||
549 | cadet_mq_error_handler (void *cls, | ||
550 | enum GNUNET_MQ_Error error) | ||
551 | { | ||
552 | struct GNUNET_CADET_Channel *ch = cls; | ||
553 | |||
554 | GNUNET_break (0); | ||
555 | if (GNUNET_MQ_ERROR_NO_MATCH == error) | ||
556 | { | ||
557 | /* Got a message we did not understand, still try to continue! */ | ||
558 | GNUNET_CADET_receive_done (ch); | ||
559 | } | ||
560 | else | ||
561 | { | ||
562 | schedule_reconnect (ch->cadet); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * Implementation function that cancels the currently sent message. | ||
569 | * Should basically undo whatever #mq_send_impl() did. | ||
570 | * | ||
571 | * @param mq message queue | ||
572 | * @param impl_state state specific to the implementation | ||
573 | */ | ||
574 | static void | ||
575 | cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, | ||
576 | void *impl_state) | ||
577 | { | ||
578 | struct GNUNET_CADET_Channel *ch = impl_state; | ||
579 | |||
580 | GNUNET_assert (NULL != ch->pending_env); | ||
581 | GNUNET_MQ_discard (ch->pending_env); | ||
582 | ch->pending_env = NULL; | ||
583 | if (NULL != ch->mq_cont) | ||
584 | { | ||
585 | GNUNET_SCHEDULER_cancel (ch->mq_cont); | ||
586 | ch->mq_cont = NULL; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * Process the new channel notification and add it to the channels in the handle | ||
593 | * | ||
594 | * @param h The cadet handle | ||
595 | * @param msg A message with the details of the new incoming channel | ||
596 | */ | ||
597 | static void | ||
598 | handle_channel_created (void *cls, | ||
599 | const struct GNUNET_CADET_LocalChannelCreateMessage *msg) | ||
600 | { | ||
601 | struct GNUNET_CADET_Handle *h = cls; | ||
602 | struct GNUNET_CADET_Channel *ch; | ||
603 | struct GNUNET_CADET_Port *port; | ||
604 | const struct GNUNET_HashCode *port_number; | ||
605 | struct GNUNET_CADET_ClientChannelNumber ccn; | ||
606 | |||
607 | ccn = msg->ccn; | ||
608 | port_number = &msg->port; | ||
609 | if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
610 | { | ||
611 | GNUNET_break (0); | ||
612 | return; | ||
613 | } | ||
614 | port = find_port (h, | ||
615 | port_number); | ||
616 | if (NULL == port) | ||
617 | { | ||
618 | /* We could have closed the port but the service didn't know about it yet | ||
619 | * This is not an error. | ||
620 | */ | ||
621 | struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg; | ||
622 | struct GNUNET_MQ_Envelope *env; | ||
623 | |||
624 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
625 | "No handler for incoming channel %X (on port %s, recently closed?)\n", | ||
626 | ntohl (ccn.channel_of_client), | ||
627 | GNUNET_h2s (port_number)); | ||
628 | env = GNUNET_MQ_msg (d_msg, | ||
629 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); | ||
630 | d_msg->ccn = msg->ccn; | ||
631 | GNUNET_MQ_send (h->mq, | ||
632 | env); | ||
633 | return; | ||
634 | } | ||
635 | |||
636 | ch = create_channel (h, | ||
637 | &ccn); | ||
638 | ch->peer = msg->peer; | ||
639 | ch->cadet = h; | ||
640 | ch->incoming_port = port; | ||
641 | ch->options = ntohl (msg->opt); | ||
642 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
643 | "Creating incoming channel %X [%s] %p\n", | ||
644 | ntohl (ccn.channel_of_client), | ||
645 | GNUNET_h2s (port_number), | ||
646 | ch); | ||
647 | |||
648 | GNUNET_assert (NULL != port->connects); | ||
649 | ch->window_changes = port->window_changes; | ||
650 | ch->disconnects = port->disconnects; | ||
651 | ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl, | ||
652 | &cadet_mq_destroy_impl, | ||
653 | &cadet_mq_cancel_impl, | ||
654 | ch, | ||
655 | port->handlers, | ||
656 | &cadet_mq_error_handler, | ||
657 | ch); | ||
658 | ch->ctx = port->connects (port->cls, | ||
659 | ch, | ||
660 | &msg->peer); | ||
661 | GNUNET_MQ_set_handlers_closure (ch->mq, | ||
662 | ch->ctx); | ||
663 | } | ||
664 | |||
665 | |||
666 | /** | ||
667 | * Process the channel destroy notification and free associated resources | ||
668 | * | ||
669 | * @param h The cadet handle | ||
670 | * @param msg A message with the details of the channel being destroyed | ||
671 | */ | ||
672 | static void | ||
673 | handle_channel_destroy (void *cls, | ||
674 | const struct GNUNET_CADET_LocalChannelDestroyMessage *msg) | ||
675 | { | ||
676 | struct GNUNET_CADET_Handle *h = cls; | ||
677 | struct GNUNET_CADET_Channel *ch; | ||
678 | |||
679 | ch = find_channel (h, | ||
680 | msg->ccn); | ||
681 | if (NULL == ch) | ||
682 | { | ||
683 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
684 | "Received channel destroy for unknown channel %X from CADET service (recently close?)\n", | ||
685 | ntohl (msg->ccn.channel_of_client)); | ||
686 | return; | ||
687 | } | ||
688 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
689 | "Received channel destroy for channel %X from CADET service\n", | ||
690 | ntohl (msg->ccn.channel_of_client)); | ||
691 | destroy_channel (ch); | ||
692 | } | ||
693 | |||
694 | |||
695 | /** | ||
696 | * Check that message received from CADET service is well-formed. | ||
697 | * | ||
698 | * @param cls the `struct GNUNET_CADET_Handle` | ||
699 | * @param message the message we got | ||
700 | * @return #GNUNET_OK if the message is well-formed, | ||
701 | * #GNUNET_SYSERR otherwise | ||
702 | */ | ||
703 | static int | ||
704 | check_local_data (void *cls, | ||
705 | const struct GNUNET_CADET_LocalData *message) | ||
706 | { | ||
707 | uint16_t size; | ||
708 | |||
709 | size = ntohs (message->header.size); | ||
710 | if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size) | ||
711 | { | ||
712 | GNUNET_break (0); | ||
713 | return GNUNET_SYSERR; | ||
714 | } | ||
715 | return GNUNET_OK; | ||
716 | } | ||
717 | |||
718 | |||
719 | /** | ||
720 | * Process the incoming data packets, call appropriate handlers. | ||
721 | * | ||
722 | * @param h The cadet handle | ||
723 | * @param message A message encapsulating the data | ||
724 | */ | ||
725 | static void | ||
726 | handle_local_data (void *cls, | ||
727 | const struct GNUNET_CADET_LocalData *message) | ||
728 | { | ||
729 | struct GNUNET_CADET_Handle *h = cls; | ||
730 | const struct GNUNET_MessageHeader *payload; | ||
731 | struct GNUNET_CADET_Channel *ch; | ||
732 | uint16_t type; | ||
733 | int fwd; | ||
734 | |||
735 | ch = find_channel (h, | ||
736 | message->ccn); | ||
737 | if (NULL == ch) | ||
738 | { | ||
739 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
740 | "Unknown channel %X for incoming data (recently closed?)\n", | ||
741 | ntohl (message->ccn.channel_of_client)); | ||
742 | return; | ||
743 | } | ||
744 | |||
745 | payload = (const struct GNUNET_MessageHeader *) &message[1]; | ||
746 | type = ntohs (payload->type); | ||
747 | fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; | ||
748 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
749 | "Got a %s data on channel %s [%X] of type %u\n", | ||
750 | fwd ? "FWD" : "BWD", | ||
751 | GNUNET_i2s (&ch->peer), | ||
752 | ntohl (message->ccn.channel_of_client), | ||
753 | type); | ||
754 | GNUNET_MQ_inject_message (ch->mq, | ||
755 | payload); | ||
756 | } | ||
757 | |||
758 | |||
759 | /** | ||
760 | * Process a local ACK message, enabling the client to send | ||
761 | * more data to the service. | ||
762 | * | ||
763 | * @param h Cadet handle. | ||
764 | * @param message Message itself. | ||
765 | */ | ||
766 | static void | ||
767 | handle_local_ack (void *cls, | ||
768 | const struct GNUNET_CADET_LocalAck *message) | ||
769 | { | ||
770 | struct GNUNET_CADET_Handle *h = cls; | ||
771 | struct GNUNET_CADET_Channel *ch; | ||
772 | |||
773 | ch = find_channel (h, | ||
774 | message->ccn); | ||
775 | if (NULL == ch) | ||
776 | { | ||
777 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
778 | "ACK on unknown channel %X\n", | ||
779 | ntohl (message->ccn.channel_of_client)); | ||
780 | return; | ||
781 | } | ||
782 | ch->allow_send++; | ||
783 | if (NULL == ch->pending_env) | ||
784 | { | ||
785 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
786 | "Got an ACK on mq channel %X, allow send now %u!\n", | ||
787 | ntohl (ch->ccn.channel_of_client), | ||
788 | ch->allow_send); | ||
789 | notify_window_size (ch); | ||
790 | return; | ||
791 | } | ||
792 | if (NULL != ch->mq_cont) | ||
793 | return; /* already working on it! */ | ||
794 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
795 | "Got an ACK on mq channel %X, sending pending message!\n", | ||
796 | ntohl (ch->ccn.channel_of_client)); | ||
797 | ch->mq_cont | ||
798 | = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now, | ||
799 | ch); | ||
800 | } | ||
801 | |||
802 | |||
803 | /** | ||
804 | * Generic error handler, called with the appropriate error code and | ||
805 | * the same closure specified at the creation of the message queue. | ||
806 | * Not every message queue implementation supports an error handler. | ||
807 | * | ||
808 | * @param cls closure, a `struct GNUNET_CORE_Handle *` | ||
809 | * @param error error code | ||
810 | */ | ||
811 | static void | ||
812 | handle_mq_error (void *cls, | ||
813 | enum GNUNET_MQ_Error error) | ||
814 | { | ||
815 | struct GNUNET_CADET_Handle *h = cls; | ||
816 | |||
817 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
818 | "MQ ERROR: %u\n", | ||
819 | error); | ||
820 | GNUNET_MQ_destroy (h->mq); | ||
821 | h->mq = NULL; | ||
822 | reconnect (h); | ||
823 | } | ||
824 | |||
825 | |||
826 | /** | ||
827 | * Process a local reply about info on all tunnels, pass info to the user. | ||
828 | * | ||
829 | * @param cls Closure (Cadet handle). | ||
830 | * @param msg Message itself. | ||
831 | */ | ||
832 | static void | ||
833 | handle_get_peers (void *cls, | ||
834 | const struct GNUNET_CADET_LocalInfoPeer *msg) | ||
835 | { | ||
836 | struct GNUNET_CADET_Handle *h = cls; | ||
837 | |||
838 | if (NULL == h->info_cb.peers_cb) | ||
839 | return; | ||
840 | h->info_cb.peers_cb (h->info_cls, | ||
841 | &msg->destination, | ||
842 | (int) ntohs (msg->tunnel), | ||
843 | (unsigned int) ntohs (msg->paths), | ||
844 | 0); | ||
845 | } | ||
846 | |||
847 | |||
848 | /** | ||
849 | * Check that message received from CADET service is well-formed. | ||
850 | * | ||
851 | * @param cls the `struct GNUNET_CADET_Handle` | ||
852 | * @param message the message we got | ||
853 | * @return #GNUNET_OK if the message is well-formed, | ||
854 | * #GNUNET_SYSERR otherwise | ||
855 | */ | ||
856 | static int | ||
857 | check_get_peer (void *cls, | ||
858 | const struct GNUNET_CADET_LocalInfoPeer *message) | ||
859 | { | ||
860 | size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer); | ||
861 | const struct GNUNET_PeerIdentity *paths_array; | ||
862 | size_t esize; | ||
863 | unsigned int epaths; | ||
864 | unsigned int paths; | ||
865 | unsigned int peers; | ||
866 | |||
867 | esize = ntohs (message->header.size); | ||
868 | if (esize < msize) | ||
869 | { | ||
870 | GNUNET_break (0); | ||
871 | return GNUNET_SYSERR; | ||
872 | } | ||
873 | if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity))) | ||
874 | { | ||
875 | GNUNET_break (0); | ||
876 | return GNUNET_SYSERR; | ||
877 | } | ||
878 | peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity); | ||
879 | epaths = ntohs (message->paths); | ||
880 | paths_array = (const struct GNUNET_PeerIdentity *) &message[1]; | ||
881 | paths = 0; | ||
882 | for (unsigned int i = 0; i < peers; i++) | ||
883 | if (0 == memcmp (&paths_array[i], | ||
884 | &message->destination, | ||
885 | sizeof (struct GNUNET_PeerIdentity))) | ||
886 | paths++; | ||
887 | if (paths != epaths) | ||
888 | { | ||
889 | GNUNET_break (0); | ||
890 | return GNUNET_SYSERR; | ||
891 | } | ||
892 | return GNUNET_OK; | ||
893 | } | ||
894 | |||
895 | |||
896 | /** | ||
897 | * Process a local peer info reply, pass info to the user. | ||
898 | * | ||
899 | * @param cls Closure (Cadet handle). | ||
900 | * @param message Message itself. | ||
901 | */ | ||
902 | static void | ||
903 | handle_get_peer (void *cls, | ||
904 | const struct GNUNET_CADET_LocalInfoPeer *message) | ||
905 | { | ||
906 | struct GNUNET_CADET_Handle *h = cls; | ||
907 | const struct GNUNET_PeerIdentity *paths_array; | ||
908 | unsigned int paths; | ||
909 | unsigned int path_length; | ||
910 | int neighbor; | ||
911 | unsigned int peers; | ||
912 | |||
913 | if (NULL == h->info_cb.peer_cb) | ||
914 | return; | ||
915 | paths = ntohs (message->paths); | ||
916 | paths_array = (const struct GNUNET_PeerIdentity *) &message[1]; | ||
917 | peers = (ntohs (message->header.size) - sizeof (*message)) | ||
918 | / sizeof (struct GNUNET_PeerIdentity); | ||
919 | path_length = 0; | ||
920 | neighbor = GNUNET_NO; | ||
921 | |||
922 | for (unsigned int i = 0; i < peers; i++) | ||
923 | { | ||
924 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
925 | " %s\n", | ||
926 | GNUNET_i2s (&paths_array[i])); | ||
927 | path_length++; | ||
928 | if (0 == memcmp (&paths_array[i], &message->destination, | ||
929 | sizeof (struct GNUNET_PeerIdentity))) | ||
930 | { | ||
931 | if (1 == path_length) | ||
932 | neighbor = GNUNET_YES; | ||
933 | path_length = 0; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | /* Call Callback with tunnel info. */ | ||
938 | paths_array = (const struct GNUNET_PeerIdentity *) &message[1]; | ||
939 | h->info_cb.peer_cb (h->info_cls, | ||
940 | &message->destination, | ||
941 | (int) ntohs (message->tunnel), | ||
942 | neighbor, | ||
943 | paths, | ||
944 | paths_array); | ||
945 | } | ||
946 | |||
947 | |||
948 | /** | ||
949 | * Process a local reply about info on all tunnels, pass info to the user. | ||
950 | * | ||
951 | * @param cls Closure (Cadet handle). | ||
952 | * @param message Message itself. | ||
953 | */ | ||
954 | static void | ||
955 | handle_get_tunnels (void *cls, | ||
956 | const struct GNUNET_CADET_LocalInfoTunnel *msg) | ||
957 | { | ||
958 | struct GNUNET_CADET_Handle *h = cls; | ||
959 | |||
960 | if (NULL == h->info_cb.tunnels_cb) | ||
961 | return; | ||
962 | h->info_cb.tunnels_cb (h->info_cls, | ||
963 | &msg->destination, | ||
964 | ntohl (msg->channels), | ||
965 | ntohl (msg->connections), | ||
966 | ntohs (msg->estate), | ||
967 | ntohs (msg->cstate)); | ||
968 | |||
969 | } | ||
970 | |||
971 | |||
972 | /** | ||
973 | * Check that message received from CADET service is well-formed. | ||
974 | * | ||
975 | * @param cls the `struct GNUNET_CADET_Handle` | ||
976 | * @param msg the message we got | ||
977 | * @return #GNUNET_OK if the message is well-formed, | ||
978 | * #GNUNET_SYSERR otherwise | ||
979 | */ | ||
980 | static int | ||
981 | check_get_tunnel (void *cls, | ||
982 | const struct GNUNET_CADET_LocalInfoTunnel *msg) | ||
983 | { | ||
984 | unsigned int ch_n; | ||
985 | unsigned int c_n; | ||
986 | size_t esize; | ||
987 | size_t msize; | ||
988 | |||
989 | /* Verify message sanity */ | ||
990 | msize = ntohs (msg->header.size); | ||
991 | esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel); | ||
992 | if (esize > msize) | ||
993 | { | ||
994 | GNUNET_break (0); | ||
995 | return GNUNET_SYSERR; | ||
996 | } | ||
997 | ch_n = ntohl (msg->channels); | ||
998 | c_n = ntohl (msg->connections); | ||
999 | esize += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber); | ||
1000 | esize += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier); | ||
1001 | if (msize != esize) | ||
1002 | { | ||
1003 | GNUNET_break_op (0); | ||
1004 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1005 | "m:%u, e: %u (%u ch, %u conn)\n", | ||
1006 | (unsigned int) msize, | ||
1007 | (unsigned int) esize, | ||
1008 | ch_n, | ||
1009 | c_n); | ||
1010 | return GNUNET_SYSERR; | ||
1011 | } | ||
1012 | return GNUNET_OK; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | /** | ||
1017 | * Process a local tunnel info reply, pass info to the user. | ||
1018 | * | ||
1019 | * @param cls Closure (Cadet handle). | ||
1020 | * @param msg Message itself. | ||
1021 | */ | ||
1022 | static void | ||
1023 | handle_get_tunnel (void *cls, | ||
1024 | const struct GNUNET_CADET_LocalInfoTunnel *msg) | ||
1025 | { | ||
1026 | struct GNUNET_CADET_Handle *h = cls; | ||
1027 | unsigned int ch_n; | ||
1028 | unsigned int c_n; | ||
1029 | const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns; | ||
1030 | const struct GNUNET_CADET_ChannelTunnelNumber *chns; | ||
1031 | |||
1032 | if (NULL == h->info_cb.tunnel_cb) | ||
1033 | return; | ||
1034 | |||
1035 | ch_n = ntohl (msg->channels); | ||
1036 | c_n = ntohl (msg->connections); | ||
1037 | |||
1038 | /* Call Callback with tunnel info. */ | ||
1039 | conns = (const struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; | ||
1040 | chns = (const struct GNUNET_CADET_ChannelTunnelNumber *) &conns[c_n]; | ||
1041 | h->info_cb.tunnel_cb (h->info_cls, | ||
1042 | &msg->destination, | ||
1043 | ch_n, | ||
1044 | c_n, | ||
1045 | chns, | ||
1046 | conns, | ||
1047 | ntohs (msg->estate), | ||
1048 | ntohs (msg->cstate)); | ||
1049 | } | ||
1050 | |||
1051 | |||
1052 | /** | ||
1053 | * Reconnect to the service, retransmit all infomation to try to restore the | ||
1054 | * original state. | ||
1055 | * | ||
1056 | * @param h handle to the cadet | ||
1057 | */ | ||
1058 | static void | ||
1059 | reconnect (struct GNUNET_CADET_Handle *h) | ||
1060 | { | ||
1061 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1062 | GNUNET_MQ_hd_fixed_size (channel_created, | ||
1063 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE, | ||
1064 | struct GNUNET_CADET_LocalChannelCreateMessage, | ||
1065 | h), | ||
1066 | GNUNET_MQ_hd_fixed_size (channel_destroy, | ||
1067 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY, | ||
1068 | struct GNUNET_CADET_LocalChannelDestroyMessage, | ||
1069 | h), | ||
1070 | GNUNET_MQ_hd_var_size (local_data, | ||
1071 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, | ||
1072 | struct GNUNET_CADET_LocalData, | ||
1073 | h), | ||
1074 | GNUNET_MQ_hd_fixed_size (local_ack, | ||
1075 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, | ||
1076 | struct GNUNET_CADET_LocalAck, | ||
1077 | h), | ||
1078 | GNUNET_MQ_hd_fixed_size (get_peers, | ||
1079 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, | ||
1080 | struct GNUNET_CADET_LocalInfoPeer, | ||
1081 | h), | ||
1082 | GNUNET_MQ_hd_var_size (get_peer, | ||
1083 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, | ||
1084 | struct GNUNET_CADET_LocalInfoPeer, | ||
1085 | h), | ||
1086 | GNUNET_MQ_hd_fixed_size (get_tunnels, | ||
1087 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, | ||
1088 | struct GNUNET_CADET_LocalInfoTunnel, | ||
1089 | h), | ||
1090 | GNUNET_MQ_hd_var_size (get_tunnel, | ||
1091 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, | ||
1092 | struct GNUNET_CADET_LocalInfoTunnel, | ||
1093 | h), | ||
1094 | GNUNET_MQ_handler_end () | ||
1095 | }; | ||
1096 | |||
1097 | h->mq = GNUNET_CLIENT_connect (h->cfg, | ||
1098 | "cadet", | ||
1099 | handlers, | ||
1100 | &handle_mq_error, | ||
1101 | h); | ||
1102 | if (NULL == h->mq) | ||
1103 | { | ||
1104 | schedule_reconnect (h); | ||
1105 | return; | ||
1106 | } | ||
1107 | h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | /** | ||
1112 | * Function called during #GNUNET_CADET_disconnect() to destroy | ||
1113 | * all channels that are still open. | ||
1114 | * | ||
1115 | * @param cls the `struct GNUNET_CADET_Handle` | ||
1116 | * @param cid chanenl ID | ||
1117 | * @param value a `struct GNUNET_CADET_Channel` to destroy | ||
1118 | * @return #GNUNET_OK (continue to iterate) | ||
1119 | */ | ||
1120 | static int | ||
1121 | destroy_channel_cb (void *cls, | ||
1122 | uint32_t cid, | ||
1123 | void *value) | ||
1124 | { | ||
1125 | /* struct GNUNET_CADET_Handle *handle = cls; */ | ||
1126 | struct GNUNET_CADET_Channel *ch = value; | ||
1127 | |||
1128 | if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) | ||
1129 | { | ||
1130 | GNUNET_break (0); | ||
1131 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1132 | "channel %X not destroyed\n", | ||
1133 | ntohl (ch->ccn.channel_of_client)); | ||
1134 | } | ||
1135 | destroy_channel (ch); | ||
1136 | return GNUNET_OK; | ||
1137 | } | ||
1138 | |||
1139 | |||
1140 | /** | ||
1141 | * Function called during #GNUNET_CADET_disconnect() to destroy | ||
1142 | * all ports that are still open. | ||
1143 | * | ||
1144 | * @param cls the `struct GNUNET_CADET_Handle` | ||
1145 | * @param id port ID | ||
1146 | * @param value a `struct GNUNET_CADET_Channel` to destroy | ||
1147 | * @return #GNUNET_OK (continue to iterate) | ||
1148 | */ | ||
1149 | static int | ||
1150 | destroy_port_cb (void *cls, | ||
1151 | const struct GNUNET_HashCode *id, | ||
1152 | void *value) | ||
1153 | { | ||
1154 | /* struct GNUNET_CADET_Handle *handle = cls; */ | ||
1155 | struct GNUNET_CADET_Port *port = value; | ||
1156 | |||
1157 | /* This is a warning, the app should have cleanly closed all open ports */ | ||
1158 | GNUNET_break (0); | ||
1159 | GNUNET_CADET_close_port (port); | ||
1160 | return GNUNET_OK; | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | /** | ||
1165 | * Disconnect from the cadet service. All channels will be destroyed. All channel | ||
1166 | * disconnect callbacks will be called on any still connected peers, notifying | ||
1167 | * about their disconnection. The registered inbound channel cleaner will be | ||
1168 | * called should any inbound channels still exist. | ||
1169 | * | ||
1170 | * @param handle connection to cadet to disconnect | ||
1171 | */ | ||
1172 | void | ||
1173 | GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle) | ||
1174 | { | ||
1175 | GNUNET_CONTAINER_multihashmap_iterate (handle->ports, | ||
1176 | &destroy_port_cb, | ||
1177 | handle); | ||
1178 | GNUNET_CONTAINER_multihashmap_destroy (handle->ports); | ||
1179 | handle->ports = NULL; | ||
1180 | GNUNET_CONTAINER_multihashmap32_iterate (handle->channels, | ||
1181 | &destroy_channel_cb, | ||
1182 | handle); | ||
1183 | GNUNET_CONTAINER_multihashmap32_destroy (handle->channels); | ||
1184 | handle->channels = NULL; | ||
1185 | if (NULL != handle->mq) | ||
1186 | { | ||
1187 | GNUNET_MQ_destroy (handle->mq); | ||
1188 | handle->mq = NULL; | ||
1189 | } | ||
1190 | if (NULL != handle->reconnect_task) | ||
1191 | { | ||
1192 | GNUNET_SCHEDULER_cancel (handle->reconnect_task); | ||
1193 | handle->reconnect_task = NULL; | ||
1194 | } | ||
1195 | GNUNET_free (handle); | ||
1196 | } | ||
1197 | |||
1198 | |||
1199 | /** | ||
1200 | * Close a port opened with @a GNUNET_CADET_open_port(). | ||
1201 | * The @a new_channel callback will no longer be called. | ||
1202 | * | ||
1203 | * @param p Port handle. | ||
1204 | */ | ||
1205 | void | ||
1206 | GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p) | ||
1207 | { | ||
1208 | struct GNUNET_CADET_PortMessage *msg; | ||
1209 | struct GNUNET_MQ_Envelope *env; | ||
1210 | |||
1211 | env = GNUNET_MQ_msg (msg, | ||
1212 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE); | ||
1213 | msg->port = p->id; | ||
1214 | GNUNET_MQ_send (p->cadet->mq, | ||
1215 | env); | ||
1216 | GNUNET_assert (GNUNET_YES == | ||
1217 | GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports, | ||
1218 | &p->id, | ||
1219 | p)); | ||
1220 | GNUNET_free_non_null (p->handlers); | ||
1221 | GNUNET_free (p); | ||
1222 | } | ||
1223 | |||
1224 | |||
1225 | /** | ||
1226 | * Destroy an existing channel. | ||
1227 | * | ||
1228 | * The existing end callback for the channel will be called immediately. | ||
1229 | * Any pending outgoing messages will be sent but no incoming messages will be | ||
1230 | * accepted and no data callbacks will be called. | ||
1231 | * | ||
1232 | * @param channel Channel handle, becomes invalid after this call. | ||
1233 | */ | ||
1234 | void | ||
1235 | GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel) | ||
1236 | { | ||
1237 | struct GNUNET_CADET_Handle *h = channel->cadet; | ||
1238 | struct GNUNET_CADET_LocalChannelDestroyMessage *msg; | ||
1239 | struct GNUNET_MQ_Envelope *env; | ||
1240 | |||
1241 | if (NULL != h->mq) | ||
1242 | { | ||
1243 | env = GNUNET_MQ_msg (msg, | ||
1244 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); | ||
1245 | msg->ccn = channel->ccn; | ||
1246 | GNUNET_MQ_send (h->mq, | ||
1247 | env); | ||
1248 | } | ||
1249 | destroy_channel (channel); | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | /** | ||
1254 | * Get information about a channel. | ||
1255 | * | ||
1256 | * @param channel Channel handle. | ||
1257 | * @param option Query (GNUNET_CADET_OPTION_*). | ||
1258 | * @param ... dependant on option, currently not used | ||
1259 | * | ||
1260 | * @return Union with an answer to the query. | ||
1261 | */ | ||
1262 | const union GNUNET_CADET_ChannelInfo * | ||
1263 | GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel, | ||
1264 | enum GNUNET_CADET_ChannelOption option, | ||
1265 | ...) | ||
1266 | { | ||
1267 | static int bool_flag; | ||
1268 | |||
1269 | switch (option) | ||
1270 | { | ||
1271 | case GNUNET_CADET_OPTION_NOBUFFER: | ||
1272 | case GNUNET_CADET_OPTION_RELIABLE: | ||
1273 | case GNUNET_CADET_OPTION_OUT_OF_ORDER: | ||
1274 | if (0 != (option & channel->options)) | ||
1275 | bool_flag = GNUNET_YES; | ||
1276 | else | ||
1277 | bool_flag = GNUNET_NO; | ||
1278 | return (const union GNUNET_CADET_ChannelInfo *) &bool_flag; | ||
1279 | break; | ||
1280 | case GNUNET_CADET_OPTION_PEER: | ||
1281 | return (const union GNUNET_CADET_ChannelInfo *) &channel->peer; | ||
1282 | break; | ||
1283 | default: | ||
1284 | GNUNET_break (0); | ||
1285 | return NULL; | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | |||
1290 | /** | ||
1291 | * Send an ack on the channel to confirm the processing of a message. | ||
1292 | * | ||
1293 | * @param ch Channel on which to send the ACK. | ||
1294 | */ | ||
1295 | void | ||
1296 | GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel) | ||
1297 | { | ||
1298 | struct GNUNET_CADET_LocalAck *msg; | ||
1299 | struct GNUNET_MQ_Envelope *env; | ||
1300 | |||
1301 | env = GNUNET_MQ_msg (msg, | ||
1302 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); | ||
1303 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1304 | "Sending ACK on channel %X\n", | ||
1305 | ntohl (channel->ccn.channel_of_client)); | ||
1306 | msg->ccn = channel->ccn; | ||
1307 | GNUNET_MQ_send (channel->cadet->mq, | ||
1308 | env); | ||
1309 | } | ||
1310 | |||
1311 | |||
1312 | /** | ||
1313 | * Send message of @a type to CADET service of @a h | ||
1314 | * | ||
1315 | * @param h handle to CADET service | ||
1316 | * @param type message type of trivial information request to send | ||
1317 | */ | ||
1318 | static void | ||
1319 | send_info_request (struct GNUNET_CADET_Handle *h, | ||
1320 | uint16_t type) | ||
1321 | { | ||
1322 | struct GNUNET_MessageHeader *msg; | ||
1323 | struct GNUNET_MQ_Envelope *env; | ||
1324 | |||
1325 | env = GNUNET_MQ_msg (msg, | ||
1326 | type); | ||
1327 | GNUNET_MQ_send (h->mq, | ||
1328 | env); | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | /** | ||
1333 | * Request a debug dump on the service's STDERR. | ||
1334 | * | ||
1335 | * WARNING: unstable API, likely to change in the future! | ||
1336 | * | ||
1337 | * @param h cadet handle | ||
1338 | */ | ||
1339 | void | ||
1340 | GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h) | ||
1341 | { | ||
1342 | send_info_request (h, | ||
1343 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP); | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | /** | ||
1348 | * Request information about peers known to the running cadet service. | ||
1349 | * The callback will be called for every peer known to the service. | ||
1350 | * Only one info request (of any kind) can be active at once. | ||
1351 | * | ||
1352 | * WARNING: unstable API, likely to change in the future! | ||
1353 | * | ||
1354 | * @param h Handle to the cadet peer. | ||
1355 | * @param callback Function to call with the requested data. | ||
1356 | * @param callback_cls Closure for @c callback. | ||
1357 | * @return #GNUNET_OK / #GNUNET_SYSERR | ||
1358 | */ | ||
1359 | int | ||
1360 | GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h, | ||
1361 | GNUNET_CADET_PeersCB callback, | ||
1362 | void *callback_cls) | ||
1363 | { | ||
1364 | if (NULL != h->info_cb.peers_cb) | ||
1365 | { | ||
1366 | GNUNET_break (0); | ||
1367 | return GNUNET_SYSERR; | ||
1368 | } | ||
1369 | send_info_request (h, | ||
1370 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); | ||
1371 | h->info_cb.peers_cb = callback; | ||
1372 | h->info_cls = callback_cls; | ||
1373 | return GNUNET_OK; | ||
1374 | } | ||
1375 | |||
1376 | |||
1377 | /** | ||
1378 | * Cancel a peer info request. The callback will not be called (anymore). | ||
1379 | * | ||
1380 | * WARNING: unstable API, likely to change in the future! | ||
1381 | * | ||
1382 | * @param h Cadet handle. | ||
1383 | * @return Closure given to GNUNET_CADET_get_peers(). | ||
1384 | */ | ||
1385 | void * | ||
1386 | GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h) | ||
1387 | { | ||
1388 | void *cls = h->info_cls; | ||
1389 | |||
1390 | h->info_cb.peers_cb = NULL; | ||
1391 | h->info_cls = NULL; | ||
1392 | return cls; | ||
1393 | } | ||
1394 | |||
1395 | |||
1396 | /** | ||
1397 | * Request information about a peer known to the running cadet peer. | ||
1398 | * The callback will be called for the tunnel once. | ||
1399 | * Only one info request (of any kind) can be active at once. | ||
1400 | * | ||
1401 | * WARNING: unstable API, likely to change in the future! | ||
1402 | * | ||
1403 | * @param h Handle to the cadet peer. | ||
1404 | * @param id Peer whose tunnel to examine. | ||
1405 | * @param callback Function to call with the requested data. | ||
1406 | * @param callback_cls Closure for @c callback. | ||
1407 | * @return #GNUNET_OK / #GNUNET_SYSERR | ||
1408 | */ | ||
1409 | int | ||
1410 | GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h, | ||
1411 | const struct GNUNET_PeerIdentity *id, | ||
1412 | GNUNET_CADET_PeerCB callback, | ||
1413 | void *callback_cls) | ||
1414 | { | ||
1415 | struct GNUNET_CADET_LocalInfo *msg; | ||
1416 | struct GNUNET_MQ_Envelope *env; | ||
1417 | |||
1418 | if (NULL != h->info_cb.peer_cb) | ||
1419 | { | ||
1420 | GNUNET_break (0); | ||
1421 | return GNUNET_SYSERR; | ||
1422 | } | ||
1423 | env = GNUNET_MQ_msg (msg, | ||
1424 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); | ||
1425 | msg->peer = *id; | ||
1426 | GNUNET_MQ_send (h->mq, | ||
1427 | env); | ||
1428 | h->info_cb.peer_cb = callback; | ||
1429 | h->info_cls = callback_cls; | ||
1430 | return GNUNET_OK; | ||
1431 | } | ||
1432 | |||
1433 | |||
1434 | /** | ||
1435 | * Request information about tunnels of the running cadet peer. | ||
1436 | * The callback will be called for every tunnel of the service. | ||
1437 | * Only one info request (of any kind) can be active at once. | ||
1438 | * | ||
1439 | * WARNING: unstable API, likely to change in the future! | ||
1440 | * | ||
1441 | * @param h Handle to the cadet peer. | ||
1442 | * @param callback Function to call with the requested data. | ||
1443 | * @param callback_cls Closure for @c callback. | ||
1444 | * @return #GNUNET_OK / #GNUNET_SYSERR | ||
1445 | */ | ||
1446 | int | ||
1447 | GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h, | ||
1448 | GNUNET_CADET_TunnelsCB callback, | ||
1449 | void *callback_cls) | ||
1450 | { | ||
1451 | if (NULL != h->info_cb.tunnels_cb) | ||
1452 | { | ||
1453 | GNUNET_break (0); | ||
1454 | return GNUNET_SYSERR; | ||
1455 | } | ||
1456 | send_info_request (h, | ||
1457 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); | ||
1458 | h->info_cb.tunnels_cb = callback; | ||
1459 | h->info_cls = callback_cls; | ||
1460 | return GNUNET_OK; | ||
1461 | } | ||
1462 | |||
1463 | |||
1464 | /** | ||
1465 | * Cancel a monitor request. The monitor callback will not be called. | ||
1466 | * | ||
1467 | * @param h Cadet handle. | ||
1468 | * @return Closure given to GNUNET_CADET_get_tunnels(). | ||
1469 | */ | ||
1470 | void * | ||
1471 | GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h) | ||
1472 | { | ||
1473 | void *cls = h->info_cls; | ||
1474 | |||
1475 | h->info_cb.tunnels_cb = NULL; | ||
1476 | h->info_cls = NULL; | ||
1477 | return cls; | ||
1478 | } | ||
1479 | |||
1480 | |||
1481 | /** | ||
1482 | * Request information about a tunnel of the running cadet peer. | ||
1483 | * The callback will be called for the tunnel once. | ||
1484 | * Only one info request (of any kind) can be active at once. | ||
1485 | * | ||
1486 | * WARNING: unstable API, likely to change in the future! | ||
1487 | * | ||
1488 | * @param h Handle to the cadet peer. | ||
1489 | * @param id Peer whose tunnel to examine. | ||
1490 | * @param callback Function to call with the requested data. | ||
1491 | * @param callback_cls Closure for @c callback. | ||
1492 | * @return #GNUNET_OK / #GNUNET_SYSERR | ||
1493 | */ | ||
1494 | int | ||
1495 | GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h, | ||
1496 | const struct GNUNET_PeerIdentity *id, | ||
1497 | GNUNET_CADET_TunnelCB callback, | ||
1498 | void *callback_cls) | ||
1499 | { | ||
1500 | struct GNUNET_CADET_LocalInfo *msg; | ||
1501 | struct GNUNET_MQ_Envelope *env; | ||
1502 | |||
1503 | if (NULL != h->info_cb.tunnel_cb) | ||
1504 | { | ||
1505 | GNUNET_break (0); | ||
1506 | return GNUNET_SYSERR; | ||
1507 | } | ||
1508 | env = GNUNET_MQ_msg (msg, | ||
1509 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); | ||
1510 | msg->peer = *id; | ||
1511 | GNUNET_MQ_send (h->mq, | ||
1512 | env); | ||
1513 | h->info_cb.tunnel_cb = callback; | ||
1514 | h->info_cls = callback_cls; | ||
1515 | return GNUNET_OK; | ||
1516 | } | ||
1517 | |||
1518 | |||
1519 | /** | ||
1520 | * Transitional function to convert an unsigned int port to a hash value. | ||
1521 | * WARNING: local static value returned, NOT reentrant! | ||
1522 | * WARNING: do not use this function for new code! | ||
1523 | * | ||
1524 | * @param port Numerical port (unsigned int format). | ||
1525 | * | ||
1526 | * @return A GNUNET_HashCode usable for the new CADET API. | ||
1527 | */ | ||
1528 | const struct GNUNET_HashCode * | ||
1529 | GC_u2h (uint32_t port) | ||
1530 | { | ||
1531 | static struct GNUNET_HashCode hash; | ||
1532 | |||
1533 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1534 | "This is a transitional function, use proper crypto hashes as CADET ports\n"); | ||
1535 | GNUNET_CRYPTO_hash (&port, | ||
1536 | sizeof (port), | ||
1537 | &hash); | ||
1538 | return &hash; | ||
1539 | } | ||
1540 | |||
1541 | |||
1542 | /** | ||
1543 | * Connect to the MQ-based cadet service. | ||
1544 | * | ||
1545 | * @param cfg Configuration to use. | ||
1546 | * | ||
1547 | * @return Handle to the cadet service NULL on error. | ||
1548 | */ | ||
1549 | struct GNUNET_CADET_Handle * | ||
1550 | GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
1551 | { | ||
1552 | struct GNUNET_CADET_Handle *h; | ||
1553 | |||
1554 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1555 | "GNUNET_CADET_connecT()\n"); | ||
1556 | h = GNUNET_new (struct GNUNET_CADET_Handle); | ||
1557 | h->cfg = cfg; | ||
1558 | h->ports = GNUNET_CONTAINER_multihashmap_create (4, | ||
1559 | GNUNET_YES); | ||
1560 | h->channels = GNUNET_CONTAINER_multihashmap32_create (4); | ||
1561 | reconnect (h); | ||
1562 | if (NULL == h->mq) | ||
1563 | { | ||
1564 | GNUNET_break (0); | ||
1565 | GNUNET_CADET_disconnect (h); | ||
1566 | return NULL; | ||
1567 | } | ||
1568 | h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); | ||
1569 | h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1570 | h->reconnect_task = NULL; | ||
1571 | |||
1572 | return h; | ||
1573 | } | ||
1574 | |||
1575 | |||
1576 | /** | ||
1577 | * Open a port to receive incomming MQ-based channels. | ||
1578 | * | ||
1579 | * @param h CADET handle. | ||
1580 | * @param port Hash identifying the port. | ||
1581 | * @param connects Function called when an incoming channel is connected. | ||
1582 | * @param connects_cls Closure for the @a connects handler. | ||
1583 | * @param window_changes Function called when the transmit window size changes. | ||
1584 | * @param disconnects Function called when a channel is disconnected. | ||
1585 | * @param handlers Callbacks for messages we care about, NULL-terminated. | ||
1586 | * @return Port handle. | ||
1587 | */ | ||
1588 | struct GNUNET_CADET_Port * | ||
1589 | GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h, | ||
1590 | const struct GNUNET_HashCode *port, | ||
1591 | GNUNET_CADET_ConnectEventHandler connects, | ||
1592 | void * connects_cls, | ||
1593 | GNUNET_CADET_WindowSizeEventHandler window_changes, | ||
1594 | GNUNET_CADET_DisconnectEventHandler disconnects, | ||
1595 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
1596 | { | ||
1597 | struct GNUNET_CADET_PortMessage *msg; | ||
1598 | struct GNUNET_MQ_Envelope *env; | ||
1599 | struct GNUNET_CADET_Port *p; | ||
1600 | |||
1601 | GNUNET_assert (NULL != connects); | ||
1602 | GNUNET_assert (NULL != disconnects); | ||
1603 | |||
1604 | p = GNUNET_new (struct GNUNET_CADET_Port); | ||
1605 | p->cadet = h; | ||
1606 | p->id = *port; | ||
1607 | p->connects = connects; | ||
1608 | p->cls = connects_cls; | ||
1609 | p->window_changes = window_changes; | ||
1610 | p->disconnects = disconnects; | ||
1611 | p->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
1612 | |||
1613 | GNUNET_assert (GNUNET_OK == | ||
1614 | GNUNET_CONTAINER_multihashmap_put (h->ports, | ||
1615 | &p->id, | ||
1616 | p, | ||
1617 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1618 | |||
1619 | env = GNUNET_MQ_msg (msg, | ||
1620 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN); | ||
1621 | msg->port = p->id; | ||
1622 | GNUNET_MQ_send (h->mq, | ||
1623 | env); | ||
1624 | return p; | ||
1625 | } | ||
1626 | |||
1627 | |||
1628 | /** | ||
1629 | * Create a new channel towards a remote peer. | ||
1630 | * | ||
1631 | * If the destination port is not open by any peer or the destination peer | ||
1632 | * does not accept the channel, #GNUNET_CADET_ChannelEndHandler will be called | ||
1633 | * for this channel. | ||
1634 | * | ||
1635 | * @param h CADET handle. | ||
1636 | * @param channel_cls Closure for the channel. It's given to: | ||
1637 | * - The disconnect handler @a disconnects | ||
1638 | * - Each message type callback in @a handlers | ||
1639 | * @param destination Peer identity the channel should go to. | ||
1640 | * @param port Identification of the destination port. | ||
1641 | * @param options CadetOption flag field, with all desired option bits set to 1. | ||
1642 | * @param window_changes Function called when the transmit window size changes. | ||
1643 | * @param disconnects Function called when the channel is disconnected. | ||
1644 | * @param handlers Callbacks for messages we care about, NULL-terminated. | ||
1645 | * @return Handle to the channel. | ||
1646 | */ | ||
1647 | struct GNUNET_CADET_Channel * | ||
1648 | GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h, | ||
1649 | void *channel_cls, | ||
1650 | const struct GNUNET_PeerIdentity *destination, | ||
1651 | const struct GNUNET_HashCode *port, | ||
1652 | enum GNUNET_CADET_ChannelOption options, | ||
1653 | GNUNET_CADET_WindowSizeEventHandler window_changes, | ||
1654 | GNUNET_CADET_DisconnectEventHandler disconnects, | ||
1655 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
1656 | { | ||
1657 | struct GNUNET_CADET_Channel *ch; | ||
1658 | struct GNUNET_CADET_LocalChannelCreateMessage *msg; | ||
1659 | struct GNUNET_MQ_Envelope *env; | ||
1660 | |||
1661 | GNUNET_assert (NULL != disconnects); | ||
1662 | ch = create_channel (h, | ||
1663 | NULL); | ||
1664 | ch->ctx = channel_cls; | ||
1665 | ch->peer = *destination; | ||
1666 | ch->options = options; | ||
1667 | ch->window_changes = window_changes; | ||
1668 | ch->disconnects = disconnects; | ||
1669 | |||
1670 | /* Create MQ for channel */ | ||
1671 | ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl, | ||
1672 | &cadet_mq_destroy_impl, | ||
1673 | &cadet_mq_cancel_impl, | ||
1674 | ch, | ||
1675 | handlers, | ||
1676 | &cadet_mq_error_handler, | ||
1677 | ch); | ||
1678 | GNUNET_MQ_set_handlers_closure (ch->mq, channel_cls); | ||
1679 | |||
1680 | /* Request channel creation to service */ | ||
1681 | env = GNUNET_MQ_msg (msg, | ||
1682 | GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE); | ||
1683 | msg->ccn = ch->ccn; | ||
1684 | msg->port = *port; | ||
1685 | msg->peer = *destination; | ||
1686 | msg->opt = htonl (options); | ||
1687 | GNUNET_MQ_send (h->mq, | ||
1688 | env); | ||
1689 | return ch; | ||
1690 | } | ||
1691 | |||
1692 | |||
1693 | /** | ||
1694 | * Obtain the message queue for a connected peer. | ||
1695 | * | ||
1696 | * @param channel The channel handle from which to get the MQ. | ||
1697 | * | ||
1698 | * @return NULL if @a channel is not yet connected. | ||
1699 | */ | ||
1700 | struct GNUNET_MQ_Handle * | ||
1701 | GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel) | ||
1702 | { | ||
1703 | return channel->mq; | ||
1704 | } | ||
1705 | |||
1706 | /* end of cadet_api.c */ | ||