aboutsummaryrefslogtreecommitdiff
path: root/src/service/cadet/gnunet-service-cadet_channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/cadet/gnunet-service-cadet_channel.c')
-rw-r--r--src/service/cadet/gnunet-service-cadet_channel.c2008
1 files changed, 2008 insertions, 0 deletions
diff --git a/src/service/cadet/gnunet-service-cadet_channel.c b/src/service/cadet/gnunet-service-cadet_channel.c
new file mode 100644
index 000000000..78658c296
--- /dev/null
+++ b/src/service/cadet/gnunet-service-cadet_channel.c
@@ -0,0 +1,2008 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2017 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 cadet/gnunet-service-cadet_channel.c
22 * @brief logical links between CADET clients
23 * @author Bartlomiej Polot
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - Congestion/flow control:
28 * + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
29 * (and figure out how/where to use this!)
30 * + figure out flow control without ACKs (unreliable traffic!)
31 * - revisit handling of 'unbuffered' traffic!
32 * (need to push down through tunnel into connection selection)
33 * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
34 * reserve more bits in 'options' to allow for buffer size control?
35 */
36#include "platform.h"
37#include "cadet.h"
38#include "gnunet_statistics_service.h"
39#include "gnunet-service-cadet_channel.h"
40#include "gnunet-service-cadet_connection.h"
41#include "gnunet-service-cadet_tunnels.h"
42#include "gnunet-service-cadet_paths.h"
43
44#define LOG(level, ...) GNUNET_log_from (level, "cadet-chn", __VA_ARGS__)
45
46/**
47 * How long do we initially wait before retransmitting?
48 */
49#define CADET_INITIAL_RETRANSMIT_TIME \
50 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
51
52/**
53 * How long do we wait before dropping state about incoming
54 * connection to closed port?
55 */
56#define TIMEOUT_CLOSED_PORT \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
58
59/**
60 * How long do we wait at least before retransmitting ever?
61 */
62#define MIN_RTT_DELAY \
63 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 75)
64
65/**
66 * Maximum message ID into the future we accept for out-of-order messages.
67 * If the message is more than this into the future, we drop it. This is
68 * important both to detect values that are actually in the past, as well
69 * as to limit adversarially triggerable memory consumption.
70 *
71 * Note that right now we have "max_pending_messages = 4" hard-coded in
72 * the logic below, so a value of 4 would suffice here. But we plan to
73 * allow larger windows in the future...
74 */
75#define MAX_OUT_OF_ORDER_DISTANCE 1024
76
77
78/**
79 * All the states a channel can be in.
80 */
81enum CadetChannelState
82{
83 /**
84 * Uninitialized status, should never appear in operation.
85 */
86 CADET_CHANNEL_NEW,
87
88 /**
89 * Channel is to a port that is not open, we're waiting for the
90 * port to be opened.
91 */
92 CADET_CHANNEL_LOOSE,
93
94 /**
95 * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
96 */
97 CADET_CHANNEL_OPEN_SENT,
98
99 /**
100 * Connection confirmed, ready to carry traffic.
101 */
102 CADET_CHANNEL_READY
103};
104
105
106/**
107 * Info needed to retry a message in case it gets lost.
108 * Note that we DO use this structure also for unreliable
109 * messages.
110 */
111struct CadetReliableMessage
112{
113 /**
114 * Double linked list, FIFO style
115 */
116 struct CadetReliableMessage *next;
117
118 /**
119 * Double linked list, FIFO style
120 */
121 struct CadetReliableMessage *prev;
122
123 /**
124 * Which channel is this message in?
125 */
126 struct CadetChannel *ch;
127
128 /**
129 * Entry in the tunnels queue for this message, NULL if it has left
130 * the tunnel. Used to cancel transmission in case we receive an
131 * ACK in time.
132 */
133 struct CadetTunnelQueueEntry *qe;
134
135 /**
136 * Data message we are trying to send.
137 */
138 struct GNUNET_CADET_ChannelAppDataMessage *data_message;
139
140 /**
141 * How soon should we retry if we fail to get an ACK?
142 * Messages in the queue are sorted by this value.
143 */
144 struct GNUNET_TIME_Absolute next_retry;
145
146 /**
147 * How long do we wait for an ACK after transmission?
148 * Use for the back-off calculation.
149 */
150 struct GNUNET_TIME_Relative retry_delay;
151
152 /**
153 * Time when we first successfully transmitted the message
154 * (that is, set @e num_transmissions to 1).
155 */
156 struct GNUNET_TIME_Absolute first_transmission_time;
157
158 /**
159 * Identifier of the connection that this message took when it
160 * was first transmitted. Only useful if @e num_transmissions is 1.
161 */
162 struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
163
164 /**
165 * How often was this message transmitted? #GNUNET_SYSERR if there
166 * was an error transmitting the message, #GNUNET_NO if it was not
167 * yet transmitted ever, otherwise the number of (re) transmissions.
168 */
169 int num_transmissions;
170};
171
172
173/**
174 * List of received out-of-order data messages.
175 */
176struct CadetOutOfOrderMessage
177{
178 /**
179 * Double linked list, FIFO style
180 */
181 struct CadetOutOfOrderMessage *next;
182
183 /**
184 * Double linked list, FIFO style
185 */
186 struct CadetOutOfOrderMessage *prev;
187
188 /**
189 * ID of the message (messages up to this point needed
190 * before we give this one to the client).
191 */
192 struct ChannelMessageIdentifier mid;
193
194 /**
195 * The envelope with the payload of the out-of-order message
196 */
197 struct GNUNET_MQ_Envelope *env;
198};
199
200
201/**
202 * Client endpoint of a `struct CadetChannel`. A channel may be a
203 * loopback channel, in which case it has two of these endpoints.
204 * Note that flow control also is required in both directions.
205 */
206struct CadetChannelClient
207{
208 /**
209 * Client handle. Not by itself sufficient to designate
210 * the client endpoint, as the same client handle may
211 * be used for both the owner and the destination, and
212 * we thus also need the channel ID to identify the client.
213 */
214 struct CadetClient *c;
215
216 /**
217 * Head of DLL of messages received out of order or while client was unready.
218 */
219 struct CadetOutOfOrderMessage *head_recv;
220
221 /**
222 * Tail DLL of messages received out of order or while client was unready.
223 */
224 struct CadetOutOfOrderMessage *tail_recv;
225
226 /**
227 * Local tunnel number for this client.
228 * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
229 * otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
230 */
231 struct GNUNET_CADET_ClientChannelNumber ccn;
232
233 /**
234 * Number of entries currently in @a head_recv DLL.
235 */
236 unsigned int num_recv;
237
238 /**
239 * Can we send data to the client?
240 */
241 int client_ready;
242};
243
244
245/**
246 * Struct containing all information regarding a channel to a remote client.
247 */
248struct CadetChannel
249{
250 /**
251 * Tunnel this channel is in.
252 */
253 struct CadetTunnel *t;
254
255 /**
256 * Client owner of the tunnel, if any.
257 * (Used if this channel represends the initiating end of the tunnel.)
258 */
259 struct CadetChannelClient *owner;
260
261 /**
262 * Client destination of the tunnel, if any.
263 * (Used if this channel represents the listening end of the tunnel.)
264 */
265 struct CadetChannelClient *dest;
266
267 /**
268 * Last entry in the tunnel's queue relating to control messages
269 * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
270 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK). Used to cancel
271 * transmission in case we receive updated information.
272 */
273 struct CadetTunnelQueueEntry *last_control_qe;
274
275 /**
276 * Head of DLL of messages sent and not yet ACK'd.
277 */
278 struct CadetReliableMessage *head_sent;
279
280 /**
281 * Tail of DLL of messages sent and not yet ACK'd.
282 */
283 struct CadetReliableMessage *tail_sent;
284
285 /**
286 * Task to resend/poll in case no ACK is received.
287 */
288 struct GNUNET_SCHEDULER_Task *retry_control_task;
289
290 /**
291 * Task to resend/poll in case no ACK is received.
292 */
293 struct GNUNET_SCHEDULER_Task *retry_data_task;
294
295 /**
296 * Last time the channel was used
297 */
298 struct GNUNET_TIME_Absolute timestamp;
299
300 /**
301 * Destination port of the channel.
302 */
303 struct GNUNET_HashCode port;
304
305 /**
306 * Hash'ed port of the channel with initiator and destination PID.
307 */
308 struct GNUNET_HashCode h_port;
309
310 /**
311 * Counter for exponential backoff.
312 */
313 struct GNUNET_TIME_Relative retry_time;
314
315 /**
316 * Bitfield of already-received messages past @e mid_recv.
317 */
318 uint64_t mid_futures;
319
320 /**
321 * Next MID expected for incoming traffic.
322 */
323 struct ChannelMessageIdentifier mid_recv;
324
325 /**
326 * Next MID to use for outgoing traffic.
327 */
328 struct ChannelMessageIdentifier mid_send;
329
330 /**
331 * Total (reliable) messages pending ACK for this channel.
332 */
333 unsigned int pending_messages;
334
335 /**
336 * Maximum (reliable) messages pending ACK for this channel
337 * before we throttle the client.
338 */
339 unsigned int max_pending_messages;
340
341 /**
342 * Number identifying this channel in its tunnel.
343 */
344 struct GNUNET_CADET_ChannelTunnelNumber ctn;
345
346 /**
347 * Channel state.
348 */
349 enum CadetChannelState state;
350
351 /**
352 * Count how many ACKs we skipped, used to prevent long
353 * sequences of ACK skipping.
354 */
355 unsigned int skip_ack_series;
356
357 /**
358 * Is the tunnel bufferless (minimum latency)?
359 */
360 int nobuffer;
361
362 /**
363 * Is the tunnel reliable?
364 */
365 int reliable;
366
367 /**
368 * Is the tunnel out-of-order?
369 */
370 int out_of_order;
371
372 /**
373 * Is this channel a loopback channel, where the destination is us again?
374 */
375 int is_loopback;
376
377 /**
378 * Flag to signal the destruction of the channel. If this is set to
379 * #GNUNET_YES the channel will be destroyed once the queue is
380 * empty.
381 */
382 int destroy;
383
384 /**
385 * Type of message to be dropped. See GCT_send.
386 */
387 uint16_t type GNUNET_PACKED;
388
389};
390
391void
392GCCH_assign_type_to_drop (struct CadetChannel *ch, const struct
393 GNUNET_CADET_RequestDropCadetMessage *message)
394{
395
396 ch->type = message->type;
397
398}
399
400
401/**
402 * Check if type of message is the one to drop.
403 * @param ch CadetChannel to check for message type to drop.
404 * @param message GNUNET_MessageHeader to compare the type with.
405 */
406int
407GCCH_is_type_to_drop (struct CadetChannel *ch, const struct
408 GNUNET_MessageHeader *message)
409{
410
411 if (ch->type == message->type)
412 {
413 ch->type = 0;
414 return GNUNET_YES;
415 }
416 else
417 return GNUNET_NO;
418}
419
420
421/**
422 * Get the static string for identification of the channel.
423 *
424 * @param ch Channel.
425 *
426 * @return Static string with the channel IDs.
427 */
428const char *
429GCCH_2s (const struct CadetChannel *ch)
430{
431 static char buf[128];
432
433 GNUNET_snprintf (buf,
434 sizeof(buf),
435 "Channel %s:%s ctn:%X(%X/%X)",
436 (GNUNET_YES == ch->is_loopback)
437 ? "loopback"
438 : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
439 GNUNET_h2s (&ch->port),
440 ch->ctn.cn,
441 (NULL == ch->owner)
442 ? 0
443 : ntohl (ch->owner->ccn.channel_of_client),
444 (NULL == ch->dest)
445 ? 0
446 : ntohl (ch->dest->ccn.channel_of_client));
447 return buf;
448}
449
450
451/**
452 * Hash the @a port and @a initiator and @a listener to
453 * calculate the "challenge" @a h_port we send to the other
454 * peer on #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN.
455 *
456 * @param[out] h_port set to the hash of @a port, @a initiator and @a listener
457 * @param port cadet port, as seen by CADET clients
458 * @param listener peer that is listining on @a port
459 */
460void
461GCCH_hash_port (struct GNUNET_HashCode *h_port,
462 const struct GNUNET_HashCode *port,
463 const struct GNUNET_PeerIdentity *listener)
464{
465 struct GNUNET_HashContext *hc;
466
467 hc = GNUNET_CRYPTO_hash_context_start ();
468 GNUNET_CRYPTO_hash_context_read (hc, port, sizeof(*port));
469 GNUNET_CRYPTO_hash_context_read (hc, listener, sizeof(*listener));
470 GNUNET_CRYPTO_hash_context_finish (hc, h_port);
471 LOG (GNUNET_ERROR_TYPE_DEBUG,
472 "Calculated port hash %s\n",
473 GNUNET_h2s (h_port));
474}
475
476
477/**
478 * Get the channel's public ID.
479 *
480 * @param ch Channel.
481 *
482 * @return ID used to identify the channel with the remote peer.
483 */
484struct GNUNET_CADET_ChannelTunnelNumber
485GCCH_get_id (const struct CadetChannel *ch)
486{
487 return ch->ctn;
488}
489
490
491/**
492 * Release memory associated with @a ccc
493 *
494 * @param ccc data structure to clean up
495 */
496static void
497free_channel_client (struct CadetChannelClient *ccc)
498{
499 struct CadetOutOfOrderMessage *com;
500
501 while (NULL != (com = ccc->head_recv))
502 {
503 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, ccc->tail_recv, com);
504 ccc->num_recv--;
505 GNUNET_MQ_discard (com->env);
506 GNUNET_free (com);
507 }
508 GNUNET_free (ccc);
509}
510
511
512/**
513 * Destroy the given channel.
514 *
515 * @param ch channel to destroy
516 */
517static void
518channel_destroy (struct CadetChannel *ch)
519{
520 struct CadetReliableMessage *crm;
521
522 while (NULL != (crm = ch->head_sent))
523 {
524 GNUNET_assert (ch == crm->ch);
525 if (NULL != crm->qe)
526 {
527 GCT_send_cancel (crm->qe);
528 crm->qe = NULL;
529 }
530 GNUNET_CONTAINER_DLL_remove (ch->head_sent, ch->tail_sent, crm);
531 GNUNET_free (crm->data_message);
532 GNUNET_free (crm);
533 }
534 if (CADET_CHANNEL_LOOSE == ch->state)
535 {
536 GSC_drop_loose_channel (&ch->h_port, ch);
537 }
538 if (NULL != ch->owner)
539 {
540 free_channel_client (ch->owner);
541 ch->owner = NULL;
542 }
543 if (NULL != ch->dest)
544 {
545 free_channel_client (ch->dest);
546 ch->dest = NULL;
547 }
548 if (NULL != ch->last_control_qe)
549 {
550 GCT_send_cancel (ch->last_control_qe);
551 ch->last_control_qe = NULL;
552 }
553 if (NULL != ch->retry_data_task)
554 {
555 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
556 ch->retry_data_task = NULL;
557 }
558 if (NULL != ch->retry_control_task)
559 {
560 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
561 ch->retry_control_task = NULL;
562 }
563 if (GNUNET_NO == ch->is_loopback)
564 {
565 GCT_remove_channel (ch->t, ch, ch->ctn);
566 ch->t = NULL;
567 }
568 GNUNET_free (ch);
569}
570
571
572/**
573 * Send a channel create message.
574 *
575 * @param cls Channel for which to send.
576 */
577static void
578send_channel_open (void *cls);
579
580
581/**
582 * Function called once the tunnel confirms that we sent the
583 * create message. Delays for a bit until we retry.
584 *
585 * @param cls our `struct CadetChannel`.
586 * @param cid identifier of the connection within the tunnel, NULL
587 * if transmission failed
588 */
589static void
590channel_open_sent_cb (void *cls,
591 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
592{
593 struct CadetChannel *ch = cls;
594
595 GNUNET_assert (NULL != ch->last_control_qe);
596 ch->last_control_qe = NULL;
597 ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
598 LOG (GNUNET_ERROR_TYPE_DEBUG,
599 "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
600 GCCH_2s (ch),
601 GNUNET_STRINGS_relative_time_to_string (ch->retry_time, GNUNET_YES));
602 ch->retry_control_task =
603 GNUNET_SCHEDULER_add_delayed (ch->retry_time, &send_channel_open, ch);
604}
605
606
607/**
608 * Send a channel open message.
609 *
610 * @param cls Channel for which to send.
611 */
612static void
613send_channel_open (void *cls)
614{
615 struct CadetChannel *ch = cls;
616 struct GNUNET_CADET_ChannelOpenMessage msgcc;
617
618 ch->retry_control_task = NULL;
619 LOG (GNUNET_ERROR_TYPE_DEBUG,
620 "Sending CHANNEL_OPEN message for %s\n",
621 GCCH_2s (ch));
622 msgcc.header.size = htons (sizeof(msgcc));
623 msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
624 // TODO This will be removed in a major release, because this will be a protocol breaking change. We set the deprecated "reliable" bit here that was removed.
625 msgcc.opt = 2;
626 msgcc.h_port = ch->h_port;
627 msgcc.ctn = ch->ctn;
628 ch->state = CADET_CHANNEL_OPEN_SENT;
629 if (NULL != ch->last_control_qe)
630 GCT_send_cancel (ch->last_control_qe);
631 ch->last_control_qe =
632 GCT_send (ch->t, &msgcc.header, &channel_open_sent_cb, ch, &msgcc.ctn);
633 GNUNET_assert (NULL == ch->retry_control_task);
634}
635
636
637/**
638 * Function called once and only once after a channel was bound
639 * to its tunnel via #GCT_add_channel() is ready for transmission.
640 * Note that this is only the case for channels that this peer
641 * initiates, as for incoming channels we assume that they are
642 * ready for transmission immediately upon receiving the open
643 * message. Used to bootstrap the #GCT_send() process.
644 *
645 * @param ch the channel for which the tunnel is now ready
646 */
647void
648GCCH_tunnel_up (struct CadetChannel *ch)
649{
650 GNUNET_assert (NULL == ch->retry_control_task);
651 LOG (GNUNET_ERROR_TYPE_DEBUG,
652 "Tunnel up, sending CHANNEL_OPEN on %s now\n",
653 GCCH_2s (ch));
654 ch->retry_control_task = GNUNET_SCHEDULER_add_now (&send_channel_open, ch);
655}
656
657
658struct CadetChannel *
659GCCH_channel_local_new (struct CadetClient *owner,
660 struct GNUNET_CADET_ClientChannelNumber ccn,
661 struct CadetPeer *destination,
662 const struct GNUNET_HashCode *port,
663 uint32_t options)
664{
665 struct CadetChannel *ch;
666 struct CadetChannelClient *ccco;
667
668 ccco = GNUNET_new (struct CadetChannelClient);
669 ccco->c = owner;
670 ccco->ccn = ccn;
671 ccco->client_ready = GNUNET_YES;
672
673 ch = GNUNET_new (struct CadetChannel);
674 ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
675 ch->nobuffer = GNUNET_NO;
676 ch->reliable = GNUNET_YES;
677 ch->out_of_order = GNUNET_NO;
678 ch->max_pending_messages =
679 (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
680 ch->owner = ccco;
681 ch->port = *port;
682 GCCH_hash_port (&ch->h_port, port, GCP_get_id (destination));
683 if (0 == GNUNET_memcmp (&my_full_id, GCP_get_id (destination)))
684 {
685 struct OpenPort *op;
686
687 ch->is_loopback = GNUNET_YES;
688 op = GNUNET_CONTAINER_multihashmap_get (open_ports, &ch->h_port);
689 if (NULL == op)
690 {
691 /* port closed, wait for it to possibly open */
692 ch->state = CADET_CHANNEL_LOOSE;
693 (void) GNUNET_CONTAINER_multihashmap_put (
694 loose_channels,
695 &ch->h_port,
696 ch,
697 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
698 LOG (GNUNET_ERROR_TYPE_DEBUG,
699 "Created loose incoming loopback channel to port %s\n",
700 GNUNET_h2s (&ch->port));
701 }
702 else
703 {
704 GCCH_bind (ch, op->c, &op->port);
705 }
706 }
707 else
708 {
709 ch->t = GCP_get_tunnel (destination, GNUNET_YES);
710 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
711 ch->ctn = GCT_add_channel (ch->t, ch);
712 }
713 GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
714 LOG (GNUNET_ERROR_TYPE_DEBUG,
715 "Created channel to port %s at peer %s for %s using %s\n",
716 GNUNET_h2s (port),
717 GCP_2s (destination),
718 GSC_2s (owner),
719 (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
720 return ch;
721}
722
723
724/**
725 * We had an incoming channel to a port that is closed.
726 * It has not been opened for a while, drop it.
727 *
728 * @param cls the channel to drop
729 */
730static void
731timeout_closed_cb (void *cls)
732{
733 struct CadetChannel *ch = cls;
734
735 ch->retry_control_task = NULL;
736 LOG (GNUNET_ERROR_TYPE_DEBUG,
737 "Closing incoming channel to port %s from peer %s due to timeout\n",
738 GNUNET_h2s (&ch->port),
739 GCP_2s (GCT_get_destination (ch->t)));
740 channel_destroy (ch);
741}
742
743
744struct CadetChannel *
745GCCH_channel_incoming_new (struct CadetTunnel *t,
746 struct GNUNET_CADET_ChannelTunnelNumber ctn,
747 const struct GNUNET_HashCode *h_port,
748 uint32_t options)
749{
750 struct CadetChannel *ch;
751 struct OpenPort *op;
752
753 ch = GNUNET_new (struct CadetChannel);
754 ch->h_port = *h_port;
755 ch->t = t;
756 ch->ctn = ctn;
757 ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
758 ch->nobuffer = GNUNET_NO;
759 ch->reliable = GNUNET_YES;
760 ch->out_of_order = GNUNET_NO;
761 ch->max_pending_messages =
762 (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
763 GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
764
765 op = GNUNET_CONTAINER_multihashmap_get (open_ports, h_port);
766 if (NULL == op)
767 {
768 /* port closed, wait for it to possibly open */
769 ch->state = CADET_CHANNEL_LOOSE;
770 (void) GNUNET_CONTAINER_multihashmap_put (
771 loose_channels,
772 &ch->h_port,
773 ch,
774 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
775 GNUNET_assert (NULL == ch->retry_control_task);
776 ch->retry_control_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
777 &timeout_closed_cb,
778 ch);
779 LOG (GNUNET_ERROR_TYPE_DEBUG,
780 "Created loose incoming channel to port %s from peer %s\n",
781 GNUNET_h2s (&ch->port),
782 GCP_2s (GCT_get_destination (ch->t)));
783 }
784 else
785 {
786 GCCH_bind (ch, op->c, &op->port);
787 }
788 GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
789 return ch;
790}
791
792
793/**
794 * Function called once the tunnel confirms that we sent the
795 * ACK message. Just remembers it was sent, we do not expect
796 * ACKs for ACKs ;-).
797 *
798 * @param cls our `struct CadetChannel`.
799 * @param cid identifier of the connection within the tunnel, NULL
800 * if transmission failed
801 */
802static void
803send_ack_cb (void *cls,
804 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
805{
806 struct CadetChannel *ch = cls;
807
808 GNUNET_assert (NULL != ch->last_control_qe);
809 ch->last_control_qe = NULL;
810}
811
812
813/**
814 * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
815 *
816 * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
817 */
818static void
819send_channel_data_ack (struct CadetChannel *ch)
820{
821 struct GNUNET_CADET_ChannelDataAckMessage msg;
822
823 if (GNUNET_NO == ch->reliable)
824 return; /* no ACKs */
825 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
826 msg.header.size = htons (sizeof(msg));
827 msg.ctn = ch->ctn;
828 msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
829 msg.futures = GNUNET_htonll (ch->mid_futures);
830 LOG (GNUNET_ERROR_TYPE_DEBUG,
831 "Sending DATA_ACK %u:%llX via %s\n",
832 (unsigned int) ntohl (msg.mid.mid),
833 (unsigned long long) ch->mid_futures,
834 GCCH_2s (ch));
835 if (NULL != ch->last_control_qe)
836 GCT_send_cancel (ch->last_control_qe);
837 ch->last_control_qe = GCT_send (ch->t, &msg.header, &send_ack_cb, ch,
838 &msg.ctn);
839}
840
841
842/**
843 * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
844 * connection is up.
845 *
846 * @param cls the `struct CadetChannel`
847 */
848static void
849send_open_ack (void *cls)
850{
851 struct CadetChannel *ch = cls;
852 struct GNUNET_CADET_ChannelOpenAckMessage msg;
853
854 ch->retry_control_task = NULL;
855 LOG (GNUNET_ERROR_TYPE_DEBUG,
856 "Sending CHANNEL_OPEN_ACK on %s\n",
857 GCCH_2s (ch));
858 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
859 msg.header.size = htons (sizeof(msg));
860 msg.reserved = htonl (0);
861 msg.ctn = ch->ctn;
862 msg.port = ch->port;
863 if (NULL != ch->last_control_qe)
864 GCT_send_cancel (ch->last_control_qe);
865 ch->last_control_qe = GCT_send (ch->t, &msg.header, &send_ack_cb, ch,
866 &msg.ctn);
867}
868
869
870/**
871 * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
872 * this channel. If the binding was successful, (re)transmit the
873 * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
874 *
875 * @param ch channel that got the duplicate open
876 * @param cti identifier of the connection that delivered the message
877 */
878void
879GCCH_handle_duplicate_open (
880 struct CadetChannel *ch,
881 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
882{
883 if (NULL == ch->dest)
884 {
885 LOG (GNUNET_ERROR_TYPE_DEBUG,
886 "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
887 GCCH_2s (ch));
888 return;
889 }
890 if (NULL != ch->retry_control_task)
891 {
892 LOG (GNUNET_ERROR_TYPE_DEBUG,
893 "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
894 GCCH_2s (ch));
895 return;
896 }
897 LOG (GNUNET_ERROR_TYPE_DEBUG,
898 "Retransmitting CHANNEL_OPEN_ACK on %s\n",
899 GCCH_2s (ch));
900 ch->retry_control_task = GNUNET_SCHEDULER_add_now (&send_open_ack, ch);
901}
902
903
904/**
905 * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
906 *
907 * @param ch channel the ack is for
908 * @param to_owner #GNUNET_YES to send to owner,
909 * #GNUNET_NO to send to dest
910 */
911static void
912send_ack_to_client (struct CadetChannel *ch, int to_owner)
913{
914 struct GNUNET_MQ_Envelope *env;
915 struct GNUNET_CADET_LocalAck *ack;
916 struct CadetChannelClient *ccc;
917
918 ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
919 if (NULL == ccc)
920 {
921 /* This can happen if we are just getting ACKs after
922 our local client already disconnected. */
923 GNUNET_assert (GNUNET_YES == ch->destroy);
924 return;
925 }
926 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
927 ack->ccn = ccc->ccn;
928 LOG (GNUNET_ERROR_TYPE_DEBUG,
929 "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
930 GSC_2s (ccc->c),
931 (GNUNET_YES == to_owner) ? "owner" : "dest",
932 ntohl (ack->ccn.channel_of_client),
933 ch->pending_messages,
934 ch->max_pending_messages);
935 GSC_send_to_client (ccc->c, env);
936}
937
938
939void
940GCCH_bind (struct CadetChannel *ch,
941 struct CadetClient *c,
942 const struct GNUNET_HashCode *port)
943{
944 uint32_t options;
945 struct CadetChannelClient *cccd;
946
947 LOG (GNUNET_ERROR_TYPE_DEBUG,
948 "Binding %s from %s to port %s of %s\n",
949 GCCH_2s (ch),
950 GCT_2s (ch->t),
951 GNUNET_h2s (&ch->port),
952 GSC_2s (c));
953 if (NULL != ch->retry_control_task)
954 {
955 /* there might be a timeout task here */
956 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
957 ch->retry_control_task = NULL;
958 }
959 options = 0;
960 cccd = GNUNET_new (struct CadetChannelClient);
961 GNUNET_assert (NULL == ch->dest);
962 ch->dest = cccd;
963 ch->port = *port;
964 cccd->c = c;
965 cccd->client_ready = GNUNET_YES;
966 cccd->ccn = GSC_bind (c,
967 ch,
968 (GNUNET_YES == ch->is_loopback)
969 ? GCP_get (&my_full_id, GNUNET_YES)
970 : GCT_get_destination (ch->t),
971 port,
972 options);
973 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
974 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
975 ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
976 if (GNUNET_YES == ch->is_loopback)
977 {
978 ch->state = CADET_CHANNEL_OPEN_SENT;
979 GCCH_handle_channel_open_ack (ch, NULL, port);
980 }
981 else
982 {
983 /* notify other peer that we accepted the connection */
984 ch->state = CADET_CHANNEL_READY;
985 ch->retry_control_task = GNUNET_SCHEDULER_add_now (&send_open_ack, ch);
986 }
987 /* give client it's initial supply of ACKs */
988 GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
989 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
990 for (unsigned int i = 0; i < ch->max_pending_messages; i++)
991 send_ack_to_client (ch, GNUNET_NO);
992}
993
994
995/**
996 * One of our clients has disconnected, tell the other one that we
997 * are finished. Done asynchronously to avoid concurrent modification
998 * issues if this is the same client.
999 *
1000 * @param cls the `struct CadetChannel` where one of the ends is now dead
1001 */
1002static void
1003signal_remote_destroy_cb (void *cls)
1004{
1005 struct CadetChannel *ch = cls;
1006 struct CadetChannelClient *ccc;
1007
1008 /* Find which end is left... */
1009 ch->retry_control_task = NULL;
1010 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1011 GSC_handle_remote_channel_destroy (ccc->c, ccc->ccn, ch);
1012 channel_destroy (ch);
1013}
1014
1015
1016/**
1017 * Destroy locally created channel. Called by the local client, so no
1018 * need to tell the client.
1019 *
1020 * @param ch channel to destroy
1021 * @param c client that caused the destruction
1022 * @param ccn client number of the client @a c
1023 */
1024void
1025GCCH_channel_local_destroy (struct CadetChannel *ch,
1026 struct CadetClient *c,
1027 struct GNUNET_CADET_ClientChannelNumber ccn)
1028{
1029 LOG (GNUNET_ERROR_TYPE_DEBUG,
1030 "%s asks for destruction of %s\n",
1031 GSC_2s (c),
1032 GCCH_2s (ch));
1033 GNUNET_assert (NULL != c);
1034 if ((NULL != ch->owner) && (c == ch->owner->c) &&
1035 (ccn.channel_of_client == ch->owner->ccn.channel_of_client))
1036 {
1037 free_channel_client (ch->owner);
1038 ch->owner = NULL;
1039 }
1040 else if ((NULL != ch->dest) && (c == ch->dest->c) &&
1041 (ccn.channel_of_client == ch->dest->ccn.channel_of_client))
1042 {
1043 free_channel_client (ch->dest);
1044 ch->dest = NULL;
1045 }
1046 else
1047 {
1048 GNUNET_assert (0);
1049 }
1050
1051 if (GNUNET_YES == ch->destroy)
1052 {
1053 /* other end already destroyed, with the local client gone, no need
1054 to finish transmissions, just destroy immediately. */
1055 channel_destroy (ch);
1056 return;
1057 }
1058 if ((NULL != ch->head_sent) && ((NULL != ch->owner) || (NULL != ch->dest)))
1059 {
1060 /* Wait for other end to destroy us as well,
1061 and otherwise allow send queue to be transmitted first */
1062 ch->destroy = GNUNET_YES;
1063 return;
1064 }
1065 if ((GNUNET_YES == ch->is_loopback) &&
1066 ((NULL != ch->owner) || (NULL != ch->dest)))
1067 {
1068 if (NULL != ch->retry_control_task)
1069 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1070 ch->retry_control_task =
1071 GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb, ch);
1072 return;
1073 }
1074 if (GNUNET_NO == ch->is_loopback)
1075 {
1076 /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
1077 switch (ch->state)
1078 {
1079 case CADET_CHANNEL_NEW:
1080 /* We gave up on a channel that we created as a client to a remote
1081 target, but that never went anywhere. Nothing to do here. */
1082 break;
1083
1084 case CADET_CHANNEL_LOOSE:
1085 break;
1086
1087 default:
1088 GCT_send_channel_destroy (ch->t, ch->ctn);
1089 }
1090 }
1091 /* Nothing left to do, just finish destruction */
1092 channel_destroy (ch);
1093}
1094
1095
1096void
1097GCCH_handle_channel_open_ack (
1098 struct CadetChannel *ch,
1099 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1100 const struct GNUNET_HashCode *port)
1101{
1102 switch (ch->state)
1103 {
1104 case CADET_CHANNEL_NEW:
1105 /* this should be impossible */
1106 GNUNET_break (0);
1107 break;
1108
1109 case CADET_CHANNEL_LOOSE:
1110 /* This makes no sense. */
1111 GNUNET_break_op (0);
1112 break;
1113
1114 case CADET_CHANNEL_OPEN_SENT:
1115 if (NULL == ch->owner)
1116 {
1117 /* We're not the owner, wrong direction! */
1118 GNUNET_break_op (0);
1119 return;
1120 }
1121 if (0 != GNUNET_memcmp (&ch->port, port))
1122 {
1123 /* Other peer failed to provide the right port,
1124 refuse connection. */
1125 GNUNET_break_op (0);
1126 return;
1127 }
1128 LOG (GNUNET_ERROR_TYPE_DEBUG,
1129 "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
1130 GCCH_2s (ch));
1131 if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
1132 {
1133 GNUNET_SCHEDULER_cancel (ch->retry_control_task);
1134 ch->retry_control_task = NULL;
1135 }
1136 ch->state = CADET_CHANNEL_READY;
1137 /* On first connect, send client as many ACKs as we allow messages
1138 to be buffered! */
1139 for (unsigned int i = 0; i < ch->max_pending_messages; i++)
1140 send_ack_to_client (ch, GNUNET_YES);
1141 break;
1142
1143 case CADET_CHANNEL_READY:
1144 /* duplicate ACK, maybe we retried the CREATE. Ignore. */
1145 LOG (GNUNET_ERROR_TYPE_DEBUG,
1146 "Received duplicate channel OPEN_ACK for %s\n",
1147 GCCH_2s (ch));
1148 GNUNET_STATISTICS_update (stats, "# duplicate CREATE_ACKs", 1, GNUNET_NO);
1149 break;
1150 }
1151}
1152
1153
1154/**
1155 * Test if element @a e1 comes before element @a e2.
1156 *
1157 * @param cls closure, to a flag where we indicate duplicate packets
1158 * @param m1 a message of to sort
1159 * @param m2 another message to sort
1160 * @return #GNUNET_YES if @a e1 < @a e2, otherwise #GNUNET_NO
1161 */
1162static int
1163is_before (void *cls,
1164 struct CadetOutOfOrderMessage *m1,
1165 struct CadetOutOfOrderMessage *m2)
1166{
1167 int *duplicate = cls;
1168 uint32_t v1 = ntohl (m1->mid.mid);
1169 uint32_t v2 = ntohl (m2->mid.mid);
1170 uint32_t delta;
1171
1172 delta = v2 - v1;
1173 if (0 == delta)
1174 *duplicate = GNUNET_YES;
1175 if (delta > (uint32_t) INT_MAX)
1176 {
1177 /* in overflow range, we can safely assume we wrapped around */
1178 return GNUNET_NO;
1179 }
1180 else
1181 {
1182 /* result is small, thus v2 > v1, thus m1 < m2 */
1183 return GNUNET_YES;
1184 }
1185}
1186
1187
1188void
1189GCCH_handle_channel_plaintext_data (
1190 struct CadetChannel *ch,
1191 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1192 const struct GNUNET_CADET_ChannelAppDataMessage *msg)
1193{
1194 struct GNUNET_MQ_Envelope *env;
1195 struct GNUNET_CADET_LocalData *ld;
1196 struct CadetChannelClient *ccc;
1197 size_t payload_size;
1198 struct CadetOutOfOrderMessage *com;
1199 int duplicate;
1200 uint32_t mid_min;
1201 uint32_t mid_max;
1202 uint32_t mid_msg;
1203 uint32_t delta;
1204
1205 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1206 if ((NULL == ch->owner) && (NULL == ch->dest))
1207 {
1208 /* This client is gone, but we still have messages to send to
1209 the other end (which is why @a ch is not yet dead). However,
1210 we cannot pass messages to our client anymore. */
1211 LOG (GNUNET_ERROR_TYPE_DEBUG,
1212 "Dropping incoming payload on %s as this end is already closed\n",
1213 GCCH_2s (ch));
1214 /* send back DESTROY notification to stop further retransmissions! */
1215 if (GNUNET_YES == ch->destroy)
1216 GCT_send_channel_destroy (ch->t, ch->ctn);
1217 return;
1218 }
1219 payload_size = ntohs (msg->header.size) - sizeof(*msg);
1220 env = GNUNET_MQ_msg_extra (ld,
1221 payload_size,
1222 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1223 ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
1224 GNUNET_memcpy (&ld[1], &msg[1], payload_size);
1225 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1226 if (GNUNET_YES == ccc->client_ready)
1227 {
1228 /*
1229 * We ad-hoc send the message if
1230 * - The channel is out-of-order
1231 * - The channel is reliable and MID matches next expected MID
1232 * - The channel is unreliable and MID is before lowest seen MID
1233 */if ((GNUNET_YES == ch->out_of_order) ||
1234 ((msg->mid.mid == ch->mid_recv.mid) && (GNUNET_YES == ch->reliable)) ||
1235 ((GNUNET_NO == ch->reliable) &&
1236 (ntohl (msg->mid.mid) >= ntohl (ch->mid_recv.mid)) &&
1237 ((NULL == ccc->head_recv) ||
1238 (ntohl (msg->mid.mid) < ntohl (ccc->head_recv->mid.mid)))))
1239 {
1240 LOG (GNUNET_ERROR_TYPE_DEBUG,
1241 "Giving %u bytes of payload with MID %u from %s to client %s\n",
1242 (unsigned int) payload_size,
1243 ntohl (msg->mid.mid),
1244 GCCH_2s (ch),
1245 GSC_2s (ccc->c));
1246 ccc->client_ready = GNUNET_NO;
1247 GSC_send_to_client (ccc->c, env);
1248 if (GNUNET_NO == ch->out_of_order)
1249 ch->mid_recv.mid = htonl (1 + ntohl (msg->mid.mid));
1250 else
1251 ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
1252 ch->mid_futures >>= 1;
1253 if ((GNUNET_YES == ch->out_of_order) && (GNUNET_NO == ch->reliable))
1254 {
1255 /* possibly shift by more if we skipped messages */
1256 uint64_t delta = htonl (msg->mid.mid) - 1 - ntohl (ch->mid_recv.mid);
1257
1258 if (delta > 63)
1259 ch->mid_futures = 0;
1260 else
1261 ch->mid_futures >>= delta;
1262 ch->mid_recv.mid = htonl (1 + ntohl (msg->mid.mid));
1263 }
1264 send_channel_data_ack (ch);
1265 return;
1266 }
1267 }
1268
1269 if (GNUNET_YES == ch->reliable)
1270 {
1271 /* check if message ought to be dropped because it is ancient/too distant/duplicate */
1272 mid_min = ntohl (ch->mid_recv.mid);
1273 mid_max = mid_min + ch->max_pending_messages;
1274 mid_msg = ntohl (msg->mid.mid);
1275 if (((uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
1276 ((uint32_t) (mid_max - mid_msg) > ch->max_pending_messages))
1277 {
1278 LOG (GNUNET_ERROR_TYPE_DEBUG,
1279 "%s at %u drops ancient or far-future message %u\n",
1280 GCCH_2s (ch),
1281 (unsigned int) mid_min,
1282 ntohl (msg->mid.mid));
1283
1284 GNUNET_STATISTICS_update (stats,
1285 "# duplicate DATA (ancient or future)",
1286 1,
1287 GNUNET_NO);
1288 GNUNET_MQ_discard (env);
1289 send_channel_data_ack (ch);
1290 return;
1291 }
1292 /* mark bit for future ACKs */
1293 delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
1294 if (delta < 64)
1295 {
1296 if (0 != (ch->mid_futures & (1LLU << delta)))
1297 {
1298 /* Duplicate within the queue, drop also */
1299 LOG (GNUNET_ERROR_TYPE_DEBUG,
1300 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1301 (unsigned int) payload_size,
1302 GCCH_2s (ch),
1303 ntohl (msg->mid.mid));
1304 GNUNET_STATISTICS_update (stats, "# duplicate DATA", 1, GNUNET_NO);
1305 GNUNET_MQ_discard (env);
1306 send_channel_data_ack (ch);
1307 return;
1308 }
1309 ch->mid_futures |= (1LLU << delta);
1310 LOG (GNUNET_ERROR_TYPE_DEBUG,
1311 "Marked bit %llX for mid %u (base: %u); now: %llX\n",
1312 (1LLU << delta),
1313 mid_msg,
1314 mid_min,
1315 (unsigned long long) ch->mid_futures);
1316 }
1317 }
1318 else /* ! ch->reliable */
1319 {
1320 struct CadetOutOfOrderMessage *next_msg;
1321
1322 /**
1323 * We always send if possible in this case.
1324 * It is guaranteed that the queued MID < received MID
1325 **/
1326 if ((NULL != ccc->head_recv) && (GNUNET_YES == ccc->client_ready))
1327 {
1328 next_msg = ccc->head_recv;
1329 LOG (GNUNET_ERROR_TYPE_DEBUG,
1330 "Giving queued MID %u from %s to client %s\n",
1331 ntohl (next_msg->mid.mid),
1332 GCCH_2s (ch),
1333 GSC_2s (ccc->c));
1334 ccc->client_ready = GNUNET_NO;
1335 GSC_send_to_client (ccc->c, next_msg->env);
1336 ch->mid_recv.mid = htonl (1 + ntohl (next_msg->mid.mid));
1337 ch->mid_futures >>= 1;
1338 send_channel_data_ack (ch);
1339 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, ccc->tail_recv, next_msg);
1340 ccc->num_recv--;
1341 /* Do not process duplicate MID */
1342 if (msg->mid.mid == next_msg->mid.mid) /* Duplicate */
1343 {
1344 /* Duplicate within the queue, drop */
1345 LOG (GNUNET_ERROR_TYPE_DEBUG,
1346 "Message on %s (mid %u) dropped, duplicate\n",
1347 GCCH_2s (ch),
1348 ntohl (msg->mid.mid));
1349 GNUNET_free (next_msg);
1350 GNUNET_MQ_discard (env);
1351 return;
1352 }
1353 GNUNET_free (next_msg);
1354 }
1355
1356 if (ntohl (msg->mid.mid) < ntohl (ch->mid_recv.mid)) /* Old */
1357 {
1358 /* Duplicate within the queue, drop */
1359 LOG (GNUNET_ERROR_TYPE_DEBUG,
1360 "Message on %s (mid %u) dropped, old.\n",
1361 GCCH_2s (ch),
1362 ntohl (msg->mid.mid));
1363 GNUNET_MQ_discard (env);
1364 return;
1365 }
1366
1367 /* Channel is unreliable, so we do not ACK. But we also cannot
1368 allow buffering everything, so check if we have space... */
1369 if (ccc->num_recv >= ch->max_pending_messages)
1370 {
1371 struct CadetOutOfOrderMessage *drop;
1372
1373 /* Yep, need to drop. Drop the oldest message in
1374 the buffer. */
1375 LOG (GNUNET_ERROR_TYPE_DEBUG,
1376 "Queue full due slow client on %s, dropping oldest message\n",
1377 GCCH_2s (ch));
1378 GNUNET_STATISTICS_update (stats,
1379 "# messages dropped due to slow client",
1380 1,
1381 GNUNET_NO);
1382 drop = ccc->head_recv;
1383 GNUNET_assert (NULL != drop);
1384 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, ccc->tail_recv, drop);
1385 ccc->num_recv--;
1386 GNUNET_MQ_discard (drop->env);
1387 GNUNET_free (drop);
1388 }
1389 }
1390
1391 /* Insert message into sorted out-of-order queue */
1392 com = GNUNET_new (struct CadetOutOfOrderMessage);
1393 com->mid = msg->mid;
1394 com->env = env;
1395 duplicate = GNUNET_NO;
1396 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
1397 is_before,
1398 &duplicate,
1399 ccc->head_recv,
1400 ccc->tail_recv,
1401 com);
1402 ccc->num_recv++;
1403 if (GNUNET_YES == duplicate)
1404 {
1405 /* Duplicate within the queue, drop also (this is not covered by
1406 the case above if "delta" >= 64, which could be the case if
1407 max_pending_messages is also >= 64 or if our client is unready
1408 and we are seeing retransmissions of the message our client is
1409 blocked on. */LOG (GNUNET_ERROR_TYPE_DEBUG,
1410 "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
1411 (unsigned int) payload_size,
1412 GCCH_2s (ch),
1413 ntohl (msg->mid.mid));
1414 GNUNET_STATISTICS_update (stats, "# duplicate DATA", 1, GNUNET_NO);
1415 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, ccc->tail_recv, com);
1416 ccc->num_recv--;
1417 GNUNET_MQ_discard (com->env);
1418 GNUNET_free (com);
1419 send_channel_data_ack (ch);
1420 return;
1421 }
1422 LOG (GNUNET_ERROR_TYPE_DEBUG,
1423 "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
1424 (GNUNET_YES == ccc->client_ready) ? "out-of-order" : "client-not-ready",
1425 (unsigned int) payload_size,
1426 GCCH_2s (ch),
1427 ntohl (ccc->ccn.channel_of_client),
1428 ccc,
1429 ntohl (msg->mid.mid),
1430 ntohl (ch->mid_recv.mid));
1431 /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
1432 the sender may already be transmitting the previous one. Needs
1433 experimental evaluation to see if/when this ACK helps or
1434 hurts. (We might even want another option.) */
1435 send_channel_data_ack (ch);
1436}
1437
1438
1439/**
1440 * Function called once the tunnel has sent one of our messages.
1441 * If the message is unreliable, simply frees the `crm`. If the
1442 * message was reliable, calculate retransmission time and
1443 * wait for ACK (or retransmit).
1444 *
1445 * @param cls the `struct CadetReliableMessage` that was sent
1446 * @param cid identifier of the connection within the tunnel, NULL
1447 * if transmission failed
1448 */
1449static void
1450data_sent_cb (void *cls,
1451 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
1452
1453
1454/**
1455 * We need to retry a transmission, the last one took too long to
1456 * be acknowledged.
1457 *
1458 * @param cls the `struct CadetChannel` where we need to retransmit
1459 */
1460static void
1461retry_transmission (void *cls)
1462{
1463 struct CadetChannel *ch = cls;
1464 struct CadetReliableMessage *crm = ch->head_sent;
1465
1466 ch->retry_data_task = NULL;
1467 GNUNET_assert (NULL == crm->qe);
1468 LOG (GNUNET_ERROR_TYPE_DEBUG,
1469 "Retrying transmission on %s of message %u\n",
1470 GCCH_2s (ch),
1471 (unsigned int) ntohl (crm->data_message->mid.mid));
1472 crm->qe = GCT_send (ch->t, &crm->data_message->header, &data_sent_cb, crm,
1473 &crm->data_message->ctn);
1474 GNUNET_assert (NULL == ch->retry_data_task);
1475}
1476
1477
1478/**
1479 * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
1480 * the queue and tell our client that it can send more.
1481 *
1482 * @param ch the channel that got the PLAINTEXT_DATA_ACK
1483 * @param cti identifier of the connection that delivered the message
1484 * @param crm the message that got acknowledged
1485 */
1486static void
1487handle_matching_ack (struct CadetChannel *ch,
1488 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1489 struct CadetReliableMessage *crm)
1490{
1491 GNUNET_CONTAINER_DLL_remove (ch->head_sent, ch->tail_sent, crm);
1492 ch->pending_messages--;
1493 GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
1494 LOG (GNUNET_ERROR_TYPE_DEBUG,
1495 "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
1496 GCCH_2s (ch),
1497 (unsigned int) ntohl (crm->data_message->mid.mid),
1498 ch->pending_messages);
1499 if (NULL != crm->qe)
1500 {
1501 GCT_send_cancel (crm->qe);
1502 crm->qe = NULL;
1503 }
1504 if ((1 == crm->num_transmissions) && (NULL != cti))
1505 {
1506 GCC_ack_observed (cti);
1507 if (0 == GNUNET_memcmp (cti, &crm->connection_taken))
1508 {
1509 GCC_latency_observed (cti,
1510 GNUNET_TIME_absolute_get_duration (
1511 crm->first_transmission_time));
1512 }
1513 }
1514 GNUNET_free (crm->data_message);
1515 GNUNET_free (crm);
1516 send_ack_to_client (ch, (NULL == ch->owner) ? GNUNET_NO : GNUNET_YES);
1517}
1518
1519
1520/**
1521 * We got an acknowledgement for payload data for a channel.
1522 * Possibly resume transmissions.
1523 *
1524 * @param ch channel that got the ack
1525 * @param cti identifier of the connection that delivered the message
1526 * @param ack details about what was received
1527 */
1528void
1529GCCH_handle_channel_plaintext_data_ack (
1530 struct CadetChannel *ch,
1531 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
1532 const struct GNUNET_CADET_ChannelDataAckMessage *ack)
1533{
1534 struct CadetReliableMessage *crm;
1535 struct CadetReliableMessage *crmn;
1536 int found;
1537 uint32_t mid_base;
1538 uint64_t mid_mask;
1539 unsigned int delta;
1540
1541 GNUNET_break (GNUNET_NO == ch->is_loopback);
1542 if (GNUNET_NO == ch->reliable)
1543 {
1544 /* not expecting ACKs on unreliable channel, odd */
1545 GNUNET_break_op (0);
1546 return;
1547 }
1548 /* mid_base is the MID of the next message that the
1549 other peer expects (i.e. that is missing!), everything
1550 LOWER (but excluding mid_base itself) was received. */
1551 mid_base = ntohl (ack->mid.mid);
1552 mid_mask = GNUNET_htonll (ack->futures);
1553 found = GNUNET_NO;
1554 for (crm = ch->head_sent; NULL != crm; crm = crmn)
1555 {
1556 crmn = crm->next;
1557 delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
1558 if (delta >= UINT_MAX - ch->max_pending_messages)
1559 {
1560 /* overflow, means crm was a bit in the past, so this ACK counts for it. */
1561 LOG (GNUNET_ERROR_TYPE_DEBUG,
1562 "Got DATA_ACK with base %u satisfying past message %u on %s\n",
1563 (unsigned int) mid_base,
1564 ntohl (crm->data_message->mid.mid),
1565 GCCH_2s (ch));
1566 handle_matching_ack (ch, cti, crm);
1567 found = GNUNET_YES;
1568 continue;
1569 }
1570 delta--;
1571 if (delta >= 64)
1572 continue;
1573 LOG (GNUNET_ERROR_TYPE_DEBUG,
1574 "Testing bit %llX for mid %u (base: %u)\n",
1575 (1LLU << delta),
1576 ntohl (crm->data_message->mid.mid),
1577 mid_base);
1578 if (0 != (mid_mask & (1LLU << delta)))
1579 {
1580 LOG (GNUNET_ERROR_TYPE_DEBUG,
1581 "Got DATA_ACK with mask for %u on %s\n",
1582 ntohl (crm->data_message->mid.mid),
1583 GCCH_2s (ch));
1584 handle_matching_ack (ch, cti, crm);
1585 found = GNUNET_YES;
1586 }
1587 }
1588 if (GNUNET_NO == found)
1589 {
1590 /* ACK for message we already dropped, might have been a
1591 duplicate ACK? Ignore. */
1592 LOG (GNUNET_ERROR_TYPE_DEBUG,
1593 "Duplicate DATA_ACK on %s, ignoring\n",
1594 GCCH_2s (ch));
1595 GNUNET_STATISTICS_update (stats, "# duplicate DATA_ACKs", 1, GNUNET_NO);
1596 return;
1597 }
1598 if (NULL != ch->retry_data_task)
1599 {
1600 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1601 ch->retry_data_task = NULL;
1602 }
1603 if ((NULL != ch->head_sent) && (NULL == ch->head_sent->qe))
1604 ch->retry_data_task = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1605 &retry_transmission,
1606 ch);
1607}
1608
1609
1610void
1611GCCH_handle_remote_destroy (
1612 struct CadetChannel *ch,
1613 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
1614{
1615 struct CadetChannelClient *ccc;
1616
1617 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1618 LOG (GNUNET_ERROR_TYPE_DEBUG,
1619 "Received remote channel DESTROY for %s\n",
1620 GCCH_2s (ch));
1621 if (GNUNET_YES == ch->destroy)
1622 {
1623 /* Local client already gone, this is instant-death. */
1624 channel_destroy (ch);
1625 return;
1626 }
1627 ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
1628 if ((NULL != ccc) && (NULL != ccc->head_recv))
1629 {
1630 LOG (GNUNET_ERROR_TYPE_WARNING,
1631 "Lost end of transmission due to remote shutdown on %s\n",
1632 GCCH_2s (ch));
1633 /* FIXME: change API to notify client about truncated transmission! */
1634 }
1635 ch->destroy = GNUNET_YES;
1636 if (NULL != ccc)
1637 GSC_handle_remote_channel_destroy (ccc->c, ccc->ccn, ch);
1638 channel_destroy (ch);
1639}
1640
1641
1642/**
1643 * Test if element @a e1 comes before element @a e2.
1644 *
1645 * @param cls closure, to a flag where we indicate duplicate packets
1646 * @param crm1 an element of to sort
1647 * @param crm2 another element to sort
1648 * @return #GNUNET_YES if @a e1 < @a e2, otherwise #GNUNET_NO
1649 */
1650static int
1651cmp_crm_by_next_retry (void *cls,
1652 struct CadetReliableMessage *crm1,
1653 struct CadetReliableMessage *crm2)
1654{
1655 if (crm1->next_retry.abs_value_us < crm2->next_retry.abs_value_us)
1656 return GNUNET_YES;
1657 return GNUNET_NO;
1658}
1659
1660
1661/**
1662 * Function called once the tunnel has sent one of our messages.
1663 * If the message is unreliable, simply frees the `crm`. If the
1664 * message was reliable, calculate retransmission time and
1665 * wait for ACK (or retransmit).
1666 *
1667 * @param cls the `struct CadetReliableMessage` that was sent
1668 * @param cid identifier of the connection within the tunnel, NULL
1669 * if transmission failed
1670 */
1671static void
1672data_sent_cb (void *cls,
1673 const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
1674{
1675 struct CadetReliableMessage *crm = cls;
1676 struct CadetChannel *ch = crm->ch;
1677
1678 GNUNET_assert (GNUNET_NO == ch->is_loopback);
1679 GNUNET_assert (NULL != crm->qe);
1680 crm->qe = NULL;
1681 GNUNET_CONTAINER_DLL_remove (ch->head_sent, ch->tail_sent, crm);
1682 if (GNUNET_NO == ch->reliable)
1683 {
1684 GNUNET_free (crm->data_message);
1685 GNUNET_free (crm);
1686 ch->pending_messages--;
1687 send_ack_to_client (ch, (NULL == ch->owner) ? GNUNET_NO : GNUNET_YES);
1688 return;
1689 }
1690 if (NULL == cid)
1691 {
1692 /* There was an error sending. */
1693 crm->num_transmissions = GNUNET_SYSERR;
1694 }
1695 else if (GNUNET_SYSERR != crm->num_transmissions)
1696 {
1697 /* Increment transmission counter, and possibly store @a cid
1698 if this was the first transmission. */
1699 crm->num_transmissions++;
1700 if (1 == crm->num_transmissions)
1701 {
1702 crm->first_transmission_time = GNUNET_TIME_absolute_get ();
1703 crm->connection_taken = *cid;
1704 GCC_ack_expected (cid);
1705 }
1706 }
1707 if ((0 == crm->retry_delay.rel_value_us) && (NULL != cid))
1708 {
1709 struct CadetConnection *cc = GCC_lookup (cid);
1710
1711 if (NULL != cc)
1712 crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
1713 else
1714 crm->retry_delay = ch->retry_time;
1715 }
1716 crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
1717 crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay, MIN_RTT_DELAY);
1718 crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
1719
1720 GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
1721 cmp_crm_by_next_retry,
1722 NULL,
1723 ch->head_sent,
1724 ch->tail_sent,
1725 crm);
1726 LOG (GNUNET_ERROR_TYPE_DEBUG,
1727 "Message %u sent, next transmission on %s in %s\n",
1728 (unsigned int) ntohl (crm->data_message->mid.mid),
1729 GCCH_2s (ch),
1730 GNUNET_STRINGS_relative_time_to_string (
1731 GNUNET_TIME_absolute_get_remaining (
1732 ch->head_sent->next_retry),
1733 GNUNET_YES));
1734 if (NULL == ch->head_sent->qe)
1735 {
1736 if (NULL != ch->retry_data_task)
1737 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1738 ch->retry_data_task = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
1739 &retry_transmission,
1740 ch);
1741 }
1742}
1743
1744
1745/**
1746 * Handle data given by a client.
1747 *
1748 * Check whether the client is allowed to send in this tunnel, save if
1749 * channel is reliable and send an ACK to the client if there is still
1750 * buffer space in the tunnel.
1751 *
1752 * @param ch Channel.
1753 * @param sender_ccn ccn of the sender
1754 * @param buf payload to transmit.
1755 * @param buf_len number of bytes in @a buf
1756 * @return #GNUNET_OK if everything goes well,
1757 * #GNUNET_SYSERR in case of an error.
1758 */
1759int
1760GCCH_handle_local_data (struct CadetChannel *ch,
1761 struct GNUNET_CADET_ClientChannelNumber sender_ccn,
1762 const char *buf,
1763 size_t buf_len)
1764{
1765 struct CadetReliableMessage *crm;
1766
1767 if (ch->pending_messages >= ch->max_pending_messages)
1768 {
1769 GNUNET_break (0); /* Fails: #5370 */
1770 return GNUNET_SYSERR;
1771 }
1772 if (GNUNET_YES == ch->destroy)
1773 {
1774 /* we are going down, drop messages */
1775 return GNUNET_OK;
1776 }
1777 ch->pending_messages++;
1778
1779 if (GNUNET_YES == ch->is_loopback)
1780 {
1781 struct CadetChannelClient *receiver;
1782 struct GNUNET_MQ_Envelope *env;
1783 struct GNUNET_CADET_LocalData *ld;
1784 int ack_to_owner;
1785
1786 env =
1787 GNUNET_MQ_msg_extra (ld, buf_len, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
1788 if ((NULL != ch->owner) &&
1789 (sender_ccn.channel_of_client == ch->owner->ccn.channel_of_client))
1790 {
1791 receiver = ch->dest;
1792 ack_to_owner = GNUNET_YES;
1793 }
1794 else if ((NULL != ch->dest) &&
1795 (sender_ccn.channel_of_client == ch->dest->ccn.channel_of_client))
1796 {
1797 receiver = ch->owner;
1798 ack_to_owner = GNUNET_NO;
1799 }
1800 else
1801 {
1802 GNUNET_free (env);
1803 GNUNET_break (0);
1804 return GNUNET_SYSERR;
1805 }
1806 GNUNET_assert (NULL != receiver);
1807 ld->ccn = receiver->ccn;
1808 GNUNET_memcpy (&ld[1], buf, buf_len);
1809 if (GNUNET_YES == receiver->client_ready)
1810 {
1811 ch->pending_messages--;
1812 GSC_send_to_client (receiver->c, env);
1813 send_ack_to_client (ch, ack_to_owner);
1814 }
1815 else
1816 {
1817 struct CadetOutOfOrderMessage *oom;
1818
1819 oom = GNUNET_new (struct CadetOutOfOrderMessage);
1820 oom->env = env;
1821 GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
1822 receiver->tail_recv,
1823 oom);
1824 receiver->num_recv++;
1825 }
1826 return GNUNET_OK;
1827 }
1828
1829 /* Everything is correct, send the message. */
1830 crm = GNUNET_malloc (sizeof(*crm));
1831 crm->ch = ch;
1832 crm->data_message = GNUNET_malloc (
1833 sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
1834 crm->data_message->header.size =
1835 htons (sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
1836 crm->data_message->header.type =
1837 htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
1838 ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
1839 crm->data_message->mid = ch->mid_send;
1840 crm->data_message->ctn = ch->ctn;
1841 GNUNET_memcpy (&crm->data_message[1], buf, buf_len);
1842 GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent, ch->tail_sent, crm);
1843 LOG (GNUNET_ERROR_TYPE_DEBUG,
1844 "Sending message %u from local client to %s with %lu bytes\n",
1845 ntohl (crm->data_message->mid.mid),
1846 GCCH_2s (ch),
1847 (unsigned long) buf_len);
1848 if (NULL != ch->retry_data_task)
1849 {
1850 GNUNET_SCHEDULER_cancel (ch->retry_data_task);
1851 ch->retry_data_task = NULL;
1852 }
1853 crm->qe = GCT_send (ch->t, &crm->data_message->header, &data_sent_cb, crm,
1854 &crm->data_message->ctn);
1855 GNUNET_assert (NULL == ch->retry_data_task);
1856 return GNUNET_OK;
1857}
1858
1859
1860void
1861GCCH_handle_local_ack (struct CadetChannel *ch,
1862 struct GNUNET_CADET_ClientChannelNumber client_ccn)
1863{
1864 struct CadetChannelClient *ccc;
1865 struct CadetOutOfOrderMessage *com;
1866
1867 if ((NULL != ch->owner) &&
1868 (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client))
1869 ccc = ch->owner;
1870 else if ((NULL != ch->dest) &&
1871 (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client))
1872 ccc = ch->dest;
1873 else
1874 GNUNET_assert (0);
1875 ccc->client_ready = GNUNET_YES;
1876 com = ccc->head_recv;
1877 if (NULL == com)
1878 {
1879 LOG (GNUNET_ERROR_TYPE_DEBUG,
1880 "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
1881 GSC_2s (ccc->c),
1882 ntohl (client_ccn.channel_of_client),
1883 GCCH_2s (ch),
1884 ntohl (ccc->ccn.channel_of_client),
1885 ccc);
1886 return; /* none pending */
1887 }
1888 if (GNUNET_YES == ch->is_loopback)
1889 {
1890 int to_owner;
1891
1892 /* Messages are always in-order, just send */
1893 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, ccc->tail_recv, com);
1894 ccc->num_recv--;
1895 GSC_send_to_client (ccc->c, com->env);
1896 /* Notify sender that we can receive more */
1897 if ((NULL != ch->owner) &&
1898 (ccc->ccn.channel_of_client == ch->owner->ccn.channel_of_client))
1899 {
1900 to_owner = GNUNET_NO;
1901 }
1902 else
1903 {
1904 GNUNET_assert ((NULL != ch->dest) && (ccc->ccn.channel_of_client ==
1905 ch->dest->ccn.channel_of_client));
1906 to_owner = GNUNET_YES;
1907 }
1908 send_ack_to_client (ch, to_owner);
1909 GNUNET_free (com);
1910 return;
1911 }
1912
1913 if ((com->mid.mid != ch->mid_recv.mid) && (GNUNET_NO == ch->out_of_order) &&
1914 (GNUNET_YES == ch->reliable))
1915 {
1916 LOG (GNUNET_ERROR_TYPE_DEBUG,
1917 "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
1918 GSC_2s (ccc->c),
1919 ntohl (ccc->ccn.channel_of_client),
1920 ntohl (com->mid.mid),
1921 ntohl (ch->mid_recv.mid));
1922 return; /* missing next one in-order */
1923 }
1924
1925 LOG (GNUNET_ERROR_TYPE_DEBUG,
1926 "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
1927 ntohl (com->mid.mid),
1928 GSC_2s (ccc->c),
1929 ntohl (ccc->ccn.channel_of_client),
1930 GCCH_2s (ch));
1931
1932 /* all good, pass next message to client */
1933 GNUNET_CONTAINER_DLL_remove (ccc->head_recv, ccc->tail_recv, com);
1934 ccc->num_recv--;
1935 /* FIXME: if unreliable, this is not aggressive
1936 enough, as it would be OK to have lost some! */
1937
1938 ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
1939 ch->mid_futures >>= 1; /* equivalent to division by 2 */
1940 ccc->client_ready = GNUNET_NO;
1941 GSC_send_to_client (ccc->c, com->env);
1942 GNUNET_free (com);
1943 send_channel_data_ack (ch);
1944 if (NULL != ccc->head_recv)
1945 return;
1946 if (GNUNET_NO == ch->destroy)
1947 return;
1948 GCT_send_channel_destroy (ch->t, ch->ctn);
1949 channel_destroy (ch);
1950}
1951
1952
1953#define LOG2(level, ...) \
1954 GNUNET_log_from_nocheck (level, "cadet-chn", __VA_ARGS__)
1955
1956
1957/**
1958 * Log channel info.
1959 *
1960 * @param ch Channel.
1961 * @param level Debug level to use.
1962 */
1963void
1964GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level)
1965{
1966#if ! defined(GNUNET_CULL_LOGGING)
1967 int do_log;
1968
1969 do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
1970 "cadet-chn",
1971 __FILE__,
1972 __FUNCTION__,
1973 __LINE__);
1974 if (0 == do_log)
1975 return;
1976
1977 if (NULL == ch)
1978 {
1979 LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
1980 return;
1981 }
1982 LOG2 (level, "CHN %s:%X (%p)\n", GCT_2s (ch->t), ch->ctn.cn, ch);
1983 if (NULL != ch->owner)
1984 {
1985 LOG2 (level,
1986 "CHN origin %s ready %s local-id: %u\n",
1987 GSC_2s (ch->owner->c),
1988 ch->owner->client_ready ? "YES" : "NO",
1989 ntohl (ch->owner->ccn.channel_of_client));
1990 }
1991 if (NULL != ch->dest)
1992 {
1993 LOG2 (level,
1994 "CHN destination %s ready %s local-id: %u\n",
1995 GSC_2s (ch->dest->c),
1996 ch->dest->client_ready ? "YES" : "NO",
1997 ntohl (ch->dest->ccn.channel_of_client));
1998 }
1999 LOG2 (level,
2000 "CHN Message IDs recv: %d (%llX), send: %d\n",
2001 ntohl (ch->mid_recv.mid),
2002 (unsigned long long) ch->mid_futures,
2003 ntohl (ch->mid_send.mid));
2004#endif
2005}
2006
2007
2008/* end of gnunet-service-cadet_channel.c */