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