aboutsummaryrefslogtreecommitdiff
path: root/src/mesh/gnunet-service-mesh_connection.c
diff options
context:
space:
mode:
authorBart Polot <bart@net.in.tum.de>2013-10-01 11:05:12 +0000
committerBart Polot <bart@net.in.tum.de>2013-10-01 11:05:12 +0000
commit6e0d1b08237cba5ce900a95f231cb0164ff3606f (patch)
tree60874299ba0be683c7ad515137b29d743a9054e9 /src/mesh/gnunet-service-mesh_connection.c
parent941a901163d150d701e12d9b0b85cbb582c114b6 (diff)
downloadgnunet-6e0d1b08237cba5ce900a95f231cb0164ff3606f.tar.gz
gnunet-6e0d1b08237cba5ce900a95f231cb0164ff3606f.zip
- too much uncommited work
Diffstat (limited to 'src/mesh/gnunet-service-mesh_connection.c')
-rw-r--r--src/mesh/gnunet-service-mesh_connection.c1583
1 files changed, 1583 insertions, 0 deletions
diff --git a/src/mesh/gnunet-service-mesh_connection.c b/src/mesh/gnunet-service-mesh_connection.c
new file mode 100644
index 000000000..93ba8766d
--- /dev/null
+++ b/src/mesh/gnunet-service-mesh_connection.c
@@ -0,0 +1,1583 @@
1/*
2 This file is part of GNUnet.
3 (C) 2001-2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file mesh/gnunet-service-mesh_connection.c
23 * @brief GNUnet MESH service connection handling
24 * @author Bartlomiej Polot
25 */
26
27#include "platform.h"
28#include "gnunet_core_service.h"
29#include "gnunet-service-mesh_connection.h"
30
31
32
33
34/**
35 * All the states a connection can be in.
36 */
37enum MeshConnectionState
38{
39 /**
40 * Uninitialized status, should never appear in operation.
41 */
42 MESH_CONNECTION_NEW,
43
44 /**
45 * Connection create message sent, waiting for ACK.
46 */
47 MESH_CONNECTION_SENT,
48
49 /**
50 * Connection ACK sent, waiting for ACK.
51 */
52 MESH_CONNECTION_ACK,
53
54 /**
55 * Connection confirmed, ready to carry traffic.
56 */
57 MESH_CONNECTION_READY,
58};
59
60
61
62/**
63 * Struct containing info about a queued transmission to this peer
64 */
65struct MeshPeerQueue
66{
67 /**
68 * DLL next
69 */
70 struct MeshPeerQueue *next;
71
72 /**
73 * DLL previous
74 */
75 struct MeshPeerQueue *prev;
76
77 /**
78 * Peer this transmission is directed to.
79 */
80 struct MeshPeer *peer;
81
82 /**
83 * Connection this message belongs to.
84 */
85 struct MeshConnection *c;
86
87 /**
88 * Is FWD in c?
89 */
90 int fwd;
91
92 /**
93 * Channel this message belongs to, if known.
94 */
95 struct MeshChannel *ch;
96
97 /**
98 * Pointer to info stucture used as cls.
99 */
100 void *cls;
101
102 /**
103 * Type of message
104 */
105 uint16_t type;
106
107 /**
108 * Size of the message
109 */
110 size_t size;
111};
112
113
114/**
115 * Struct to encapsulate all the Flow Control information to a peer to which
116 * we are directly connected (on a core level).
117 */
118struct MeshFlowControl
119{
120 /**
121 * Connection this controls.
122 */
123 struct MeshConnection *c;
124
125 /**
126 * How many messages are in the queue on this connection.
127 */
128 unsigned int queue_n;
129
130 /**
131 * How many messages do we accept in the queue.
132 */
133 unsigned int queue_max;
134
135 /**
136 * Next ID to use.
137 */
138 uint32_t next_pid;
139
140 /**
141 * ID of the last packet sent towards the peer.
142 */
143 uint32_t last_pid_sent;
144
145 /**
146 * ID of the last packet received from the peer.
147 */
148 uint32_t last_pid_recv;
149
150 /**
151 * Last ACK sent to the peer (peer can't send more than this PID).
152 */
153 uint32_t last_ack_sent;
154
155 /**
156 * Last ACK sent towards the origin (for traffic towards leaf node).
157 */
158 uint32_t last_ack_recv;
159
160 /**
161 * Task to poll the peer in case of a lost ACK causes stall.
162 */
163 GNUNET_SCHEDULER_TaskIdentifier poll_task;
164
165 /**
166 * How frequently to poll for ACKs.
167 */
168 struct GNUNET_TIME_Relative poll_time;
169};
170
171
172/**
173 * Struct containing all information regarding a connection to a peer.
174 */
175struct MeshConnection
176{
177 /**
178 * DLL
179 */
180 struct MeshConnection *next;
181 struct MeshConnection *prev;
182
183 /**
184 * Tunnel this connection is part of.
185 */
186 struct MeshTunnel2 *t;
187
188 /**
189 * Flow control information for traffic fwd.
190 */
191 struct MeshFlowControl fwd_fc;
192
193 /**
194 * Flow control information for traffic bck.
195 */
196 struct MeshFlowControl bck_fc;
197
198 /**
199 * ID of the connection.
200 */
201 struct GNUNET_HashCode id;
202
203 /**
204 * State of the connection.
205 */
206 enum MeshConnectionState state;
207
208 /**
209 * Path being used for the tunnel.
210 */
211 struct MeshPeerPath *path;
212
213 /**
214 * Position of the local peer in the path.
215 */
216 unsigned int own_pos;
217
218 /**
219 * Task to keep the used paths alive at the owner,
220 * time tunnel out on all the other peers.
221 */
222 GNUNET_SCHEDULER_TaskIdentifier fwd_maintenance_task;
223
224 /**
225 * Task to keep the used paths alive at the destination,
226 * time tunnel out on all the other peers.
227 */
228 GNUNET_SCHEDULER_TaskIdentifier bck_maintenance_task;
229
230 /**
231 * Pending message count.
232 */
233 int pending_messages;
234
235 /**
236 * Destroy flag: if true, destroy on last message.
237 */
238 int destroy;
239};
240
241
242
243
244
245
246/**
247 * Connections known, indexed by cid (MeshConnection).
248 */
249static struct GNUNET_CONTAINER_MultiHashMap *connections;
250
251/**
252 * How many connections are we willing to maintain.
253 * Local connections are always allowed, even if there are more connections than max.
254 */
255static unsigned long long max_connections;
256
257/**
258 * How many messages *in total* are we willing to queue, divide by number of
259 * connections to get connection queue size.
260 */
261static unsigned long long max_msgs_queue;
262
263/**
264 * How often to send path keepalives. Paths timeout after 4 missed.
265 */
266static struct GNUNET_TIME_Relative refresh_connection_time;
267
268
269
270
271/**
272 * Initialize a Flow Control structure to the initial state.
273 *
274 * @param fc Flow Control structure to initialize.
275 */
276static void
277fc_init (struct MeshFlowControl *fc)
278{
279 fc->next_pid = 0;
280 fc->last_pid_sent = (uint32_t) -1; /* Next (expected) = 0 */
281 fc->last_pid_recv = (uint32_t) -1;
282 fc->last_ack_sent = (uint32_t) 0;
283 fc->last_ack_recv = (uint32_t) 0;
284 fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
285 fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
286 fc->queue_n = 0;
287 fc->queue_max = (max_msgs_queue / max_connections) + 1;
288}
289
290
291/**
292 * Find a connection.
293 *
294 * @param cid Connection ID.
295 */
296static struct MeshConnection *
297connection_get (const struct GNUNET_HashCode *cid)
298{
299 return GNUNET_CONTAINER_multihashmap_get (connections, cid);
300}
301
302
303/**
304 * Get first sendable message.
305 *
306 * @param peer The destination peer.
307 *
308 * @return Best current known path towards the peer, if any.
309 */
310static struct MeshPeerQueue *
311peer_get_first_message (const struct MeshPeer *peer)
312{
313 struct MeshPeerQueue *q;
314
315 for (q = peer->queue_head; NULL != q; q = q->next)
316 {
317 if (queue_is_sendable (q))
318 return q;
319 }
320
321 return NULL;
322}
323
324
325static int
326queue_is_sendable (struct MeshPeerQueue *q)
327{
328 struct MeshFlowControl *fc;
329
330 /* Is PID-independent? */
331 switch (q->type)
332 {
333 case GNUNET_MESSAGE_TYPE_MESH_ACK:
334 case GNUNET_MESSAGE_TYPE_MESH_POLL:
335 return GNUNET_YES;
336 }
337
338 /* Is PID allowed? */
339 fc = q->fwd ? &q->c->fwd_fc : &q->c->bck_fc;
340 if (GMC_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
341 return GNUNET_YES;
342
343 return GNUNET_NO;
344}
345
346
347
348/**
349 * Free a transmission that was already queued with all resources
350 * associated to the request.
351 *
352 * @param queue Queue handler to cancel.
353 * @param clear_cls Is it necessary to free associated cls?
354 */
355static void
356queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
357{
358 struct MeshPeer *peer;
359 struct MeshFlowControl *fc;
360 int fwd;
361
362 fwd = queue->fwd;
363 peer = queue->peer;
364 GNUNET_assert (NULL != queue->c);
365 fc = fwd ? &queue->c->fwd_fc : &queue->c->bck_fc;
366
367 if (GNUNET_YES == clear_cls)
368 {
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " queue destroy type %s\n",
370 GNUNET_MESH_DEBUG_M2S (queue->type));
371 switch (queue->type)
372 {
373 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_DESTROY:
374 case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
375 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "destroying a DESTROY message\n");
376 GNUNET_break (GNUNET_YES == queue->c->destroy);
377 /* fall through */
378 case GNUNET_MESSAGE_TYPE_MESH_FWD:
379 case GNUNET_MESSAGE_TYPE_MESH_BCK:
380 case GNUNET_MESSAGE_TYPE_MESH_ACK:
381 case GNUNET_MESSAGE_TYPE_MESH_POLL:
382 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
383 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
384 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN:
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " prebuilt message\n");;
386 GNUNET_free_non_null (queue->cls);
387 break;
388
389 default:
390 GNUNET_break (0);
391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " type %s unknown!\n",
392 GNUNET_MESH_DEBUG_M2S (queue->type));
393 }
394
395 }
396 GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
397
398 if (queue->type != GNUNET_MESSAGE_TYPE_MESH_ACK &&
399 queue->type != GNUNET_MESSAGE_TYPE_MESH_POLL)
400 {
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Q_N- %p %u\n", fc, fc->queue_n);
402 fc->queue_n--;
403 peer->queue_n--;
404 }
405 if (NULL != queue->c)
406 {
407 queue->c->pending_messages--;
408 if (NULL != queue->c->t)
409 {
410 queue->c->t->pending_messages--;
411 }
412 }
413
414 GNUNET_free (queue);
415}
416
417
418
419static size_t
420queue_send (void *cls, size_t size, void *buf)
421{
422 struct MeshPeer *peer = cls;
423 struct MeshFlowControl *fc;
424 struct MeshConnection *c;
425 struct GNUNET_MessageHeader *msg;
426 struct MeshPeerQueue *queue;
427 struct MeshTunnel2 *t;
428 struct MeshChannel *ch;
429 const struct GNUNET_PeerIdentity *dst_id;
430 size_t data_size;
431 uint32_t pid;
432 uint16_t type;
433 int fwd;
434
435 peer->core_transmit = NULL;
436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Queue send (max %u)\n", size);
437
438 if (NULL == buf || 0 == size)
439 {
440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Buffer size 0.\n");
441 return 0;
442 }
443
444 /* Initialize */
445 queue = peer_get_first_message (peer);
446 if (NULL == queue)
447 {
448 GNUNET_break (0); /* Core tmt_rdy should've been canceled */
449 return 0;
450 }
451 c = queue->c;
452 fwd = queue->fwd;
453 fc = fwd ? &c->fwd_fc : &c->bck_fc;
454
455 dst_id = GNUNET_PEER_resolve2 (peer->id);
456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* towards %s\n", GNUNET_i2s (dst_id));
457 /* Check if buffer size is enough for the message */
458 if (queue->size > size)
459 {
460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* not enough room, reissue\n");
461 peer->core_transmit =
462 GNUNET_CORE_notify_transmit_ready (core_handle,
463 GNUNET_NO,
464 0,
465 GNUNET_TIME_UNIT_FOREVER_REL,
466 dst_id,
467 queue->size,
468 &queue_send,
469 peer);
470 return 0;
471 }
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* size %u ok\n", queue->size);
473
474 t = (NULL != c) ? c->t : NULL;
475 type = 0;
476
477 /* Fill buf */
478 switch (queue->type)
479 {
480 case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
481 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_DESTROY:
482 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN:
483 case GNUNET_MESSAGE_TYPE_MESH_FWD:
484 case GNUNET_MESSAGE_TYPE_MESH_BCK:
485 case GNUNET_MESSAGE_TYPE_MESH_ACK:
486 case GNUNET_MESSAGE_TYPE_MESH_POLL:
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "* raw: %s\n",
489 GNUNET_MESH_DEBUG_M2S (queue->type));
490 data_size = send_core_data_raw (queue->cls, size, buf);
491 msg = (struct GNUNET_MessageHeader *) buf;
492 type = ntohs (msg->type);
493 break;
494 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* path create\n");
496 if (GMC_is_origin (c, GNUNET_YES))
497 data_size = send_core_connection_create (queue->c, size, buf);
498 else
499 data_size = send_core_data_raw (queue->cls, size, buf);
500 break;
501 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* path ack\n");
503 if (GMC_is_origin (c, GNUNET_NO) ||
504 GMC_is_origin (c, GNUNET_YES))
505 data_size = send_core_connection_ack (queue->c, size, buf);
506 else
507 data_size = send_core_data_raw (queue->cls, size, buf);
508 break;
509 case GNUNET_MESSAGE_TYPE_MESH_DATA:
510 case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
511 case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
512 /* This should be encapsulted */
513 GNUNET_break (0);
514 data_size = 0;
515 break;
516 default:
517 GNUNET_break (0);
518 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "* type unknown: %u\n",
519 queue->type);
520 data_size = 0;
521 }
522
523 if (0 < drop_percent &&
524 GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
525 {
526 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
527 "Dropping message of type %s\n",
528 GNUNET_MESH_DEBUG_M2S (queue->type));
529 data_size = 0;
530 }
531
532 /* Free queue, but cls was freed by send_core_* */
533 ch = queue->ch;
534 queue_destroy (queue, GNUNET_NO);
535
536 /* Send ACK if needed, after accounting for sent ID in fc->queue_n */
537 switch (type)
538 {
539 case GNUNET_MESSAGE_TYPE_MESH_FWD:
540 case GNUNET_MESSAGE_TYPE_MESH_BCK:
541 pid = ntohl ( ((struct GNUNET_MESH_Encrypted *) buf)->pid );
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* accounting pid %u\n", pid);
543 fc->last_pid_sent = pid;
544 send_ack (c, ch, fwd);
545 break;
546 default:
547 break;
548 }
549
550 /* If more data in queue, send next */
551 queue = peer_get_first_message (peer);
552 if (NULL != queue)
553 {
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* more data!\n");
555 if (NULL == peer->core_transmit) {
556 peer->core_transmit =
557 GNUNET_CORE_notify_transmit_ready(core_handle,
558 0,
559 0,
560 GNUNET_TIME_UNIT_FOREVER_REL,
561 dst_id,
562 queue->size,
563 &queue_send,
564 peer);
565 }
566 else
567 {
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569 "* tmt rdy called somewhere else\n");
570 }
571 if (GNUNET_SCHEDULER_NO_TASK == fc->poll_task)
572 {
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* starting poll timeout\n");
574 fc->poll_task =
575 GNUNET_SCHEDULER_add_delayed (fc->poll_time, &connection_poll, fc);
576 }
577 }
578 else
579 {
580 if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
581 {
582 GNUNET_SCHEDULER_cancel (fc->poll_task);
583 fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
584 }
585 }
586 if (NULL != c)
587 {
588 c->pending_messages--;
589 if (GNUNET_YES == c->destroy && 0 == c->pending_messages)
590 {
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* destroying connection!\n");
592 GMC_destroy (c);
593 }
594 }
595
596 if (NULL != t)
597 {
598 t->pending_messages--;
599 if (GNUNET_YES == t->destroy && 0 == t->pending_messages)
600 {
601// GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* destroying tunnel!\n");
602 tunnel_destroy (t);
603 }
604 }
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Return %d\n", data_size);
606 return data_size;
607}
608
609
610
611static void
612queue_add (void *cls, uint16_t type, size_t size,
613 struct MeshConnection *c,
614 struct MeshChannel *ch,
615 int fwd)
616{
617 struct MeshPeerQueue *queue;
618 struct MeshFlowControl *fc;
619 struct MeshPeer *peer;
620 int priority;
621 int call_core;
622
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 "queue add %s %s (%u) on c %p, ch %p\n",
625 fwd ? "FWD" : "BCK", GNUNET_MESH_DEBUG_M2S (type), size, c, ch);
626 GNUNET_assert (NULL != c);
627
628 fc = fwd ? &c->fwd_fc : &c->bck_fc;
629 peer = fwd ? connection_get_next_hop (c) : connection_get_prev_hop (c);
630
631 if (NULL == fc)
632 {
633 GNUNET_break (0);
634 return;
635 }
636
637 if (NULL == peer->connections)
638 {
639 /* We are not connected to this peer, ignore request. */
640 GNUNET_break_op (0);
641 return;
642 }
643
644 priority = 0;
645
646 if (GNUNET_MESSAGE_TYPE_MESH_POLL == type ||
647 GNUNET_MESSAGE_TYPE_MESH_ACK == type)
648 {
649 priority = 100;
650 }
651
652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "fc %p\n", fc);
654 if (fc->queue_n >= fc->queue_max && 0 == priority)
655 {
656 GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)",
657 1, GNUNET_NO);
658 GNUNET_break (0);
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "queue full: %u/%u\n",
661 fc->queue_n, fc->queue_max);
662 return; /* Drop this message */
663 }
664
665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "last pid %u\n", fc->last_pid_sent);
666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", fc->last_ack_recv);
667 if (GMC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
668 {
669 call_core = GNUNET_NO;
670 if (GNUNET_SCHEDULER_NO_TASK == fc->poll_task &&
671 GNUNET_MESSAGE_TYPE_MESH_POLL != type)
672 {
673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
674 "no buffer space (%u > %u): starting poll\n",
675 fc->last_pid_sent + 1, fc->last_ack_recv);
676 fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
677 &connection_poll,
678 fc);
679 }
680 }
681 else
682 call_core = GNUNET_YES;
683 queue = GNUNET_malloc (sizeof (struct MeshPeerQueue));
684 queue->cls = cls;
685 queue->type = type;
686 queue->size = size;
687 queue->peer = peer;
688 queue->c = c;
689 queue->ch = ch;
690 queue->fwd = fwd;
691 if (100 <= priority)
692 {
693 struct MeshPeerQueue *copy;
694 struct MeshPeerQueue *next;
695
696 for (copy = peer->queue_head; NULL != copy; copy = next)
697 {
698 next = copy->next;
699 if (copy->type == type && copy->c == c && copy->fwd == fwd)
700 {
701 /* Example: also a FWD ACK for connection XYZ */
702 queue_destroy (copy, GNUNET_YES);
703 }
704 }
705 GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, queue);
706 }
707 else
708 {
709 GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail, queue);
710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n);
711 fc->queue_n++;
712 peer->queue_n++;
713 }
714
715 if (NULL == peer->core_transmit && GNUNET_YES == call_core)
716 {
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "calling core tmt rdy towards %s for %u bytes\n",
719 peer2s (peer), size);
720 peer->core_transmit =
721 GNUNET_CORE_notify_transmit_ready (core_handle,
722 0,
723 0,
724 GNUNET_TIME_UNIT_FOREVER_REL,
725 GNUNET_PEER_resolve2 (peer->id),
726 size,
727 &queue_send,
728 peer);
729 }
730 else
731 {
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
733 "core tmt rdy towards %s already called\n",
734 peer2s (peer));
735
736 }
737 c->pending_messages++;
738 if (NULL != c->t)
739 c->t->pending_messages++;
740}
741
742
743
744
745/**
746 * Sends an already built message on a connection, properly registering
747 * all used resources.
748 *
749 * @param message Message to send. Function makes a copy of it.
750 * If message is not hop-by-hop, decrements TTL of copy.
751 * @param c Connection on which this message is transmitted.
752 * @param ch Channel on which this message is transmitted, or NULL.
753 * @param fwd Is this a fwd message?
754 */
755static void
756send_prebuilt_message_connection (const struct GNUNET_MessageHeader *message,
757 struct MeshConnection *c,
758 struct MeshChannel *ch,
759 int fwd)
760{
761 void *data;
762 size_t size;
763 uint16_t type;
764
765 size = ntohs (message->size);
766 data = GNUNET_malloc (size);
767 memcpy (data, message, size);
768 type = ntohs (message->type);
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Send %s (%u) on connection %s\n",
770 GNUNET_MESH_DEBUG_M2S (type), size, GNUNET_h2s (&c->id));
771
772 switch (type)
773 {
774 struct GNUNET_MESH_Encrypted *emsg;
775 struct GNUNET_MESH_ACK *amsg;
776 struct GNUNET_MESH_Poll *pmsg;
777 struct GNUNET_MESH_ConnectionDestroy *dmsg;
778 struct GNUNET_MESH_ConnectionBroken *bmsg;
779 uint32_t ttl;
780
781 case GNUNET_MESSAGE_TYPE_MESH_FWD:
782 case GNUNET_MESSAGE_TYPE_MESH_BCK:
783 emsg = (struct GNUNET_MESH_Encrypted *) data;
784 ttl = ntohl (emsg->ttl);
785 if (0 == ttl)
786 {
787 GNUNET_break_op (0);
788 return;
789 }
790 emsg->cid = c->id;
791 emsg->ttl = htonl (ttl - 1);
792 emsg->pid = htonl (fwd ? c->fwd_fc.next_pid++ : c->bck_fc.next_pid++);
793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " pid %u\n", ntohl (emsg->pid));
794 break;
795
796 case GNUNET_MESSAGE_TYPE_MESH_ACK:
797 amsg = (struct GNUNET_MESH_ACK *) data;
798 amsg->cid = c->id;
799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ntohl (amsg->ack));
800 break;
801
802 case GNUNET_MESSAGE_TYPE_MESH_POLL:
803 pmsg = (struct GNUNET_MESH_Poll *) data;
804 pmsg->cid = c->id;
805 pmsg->pid = htonl (fwd ? c->fwd_fc.last_pid_sent : c->bck_fc.last_pid_sent);
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " poll %u\n", ntohl (pmsg->pid));
807 break;
808
809 case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
810 dmsg = (struct GNUNET_MESH_ConnectionDestroy *) data;
811 dmsg->cid = c->id;
812 dmsg->reserved = 0;
813 break;
814
815 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN:
816 bmsg = (struct GNUNET_MESH_ConnectionBroken *) data;
817 bmsg->cid = c->id;
818 bmsg->reserved = 0;
819 break;
820
821 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
822 case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
823 break;
824
825 default:
826 GNUNET_break (0);
827 }
828
829 queue_add (data,
830 type,
831 size,
832 c,
833 ch,
834 fwd);
835}
836
837
838
839
840struct MeshConnection *
841GMC_new (const struct GNUNET_HashCode *cid)
842{
843 struct MeshConnection *c;
844
845 c = GNUNET_new (struct MeshConnection);
846 c->id = *cid;
847 GNUNET_CONTAINER_multihashmap_put (connections, &c->id, c,
848 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
849 fc_init (&c->fwd_fc);
850 fc_init (&c->bck_fc);
851 c->fwd_fc.c = c;
852 c->bck_fc.c = c;
853
854 return c;
855}
856
857
858static void
859GMC_destroy (struct MeshConnection *c)
860{
861 struct MeshPeer *peer;
862
863 if (NULL == c)
864 return;
865
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s[%X]\n",
867 peer2s (c->t->peer),
868 c->id);
869
870 /* Cancel all traffic */
871 connection_cancel_queues (c, GNUNET_YES);
872 connection_cancel_queues (c, GNUNET_NO);
873
874 /* Cancel maintainance task (keepalive/timeout) */
875 if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task)
876 GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
877 if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task)
878 GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
879
880 /* Deregister from neighbors */
881 peer = connection_get_next_hop (c);
882 if (NULL != peer && NULL != peer->connections)
883 GNUNET_CONTAINER_multihashmap_remove (peer->connections, &c->id, c);
884 peer = connection_get_prev_hop (c);
885 if (NULL != peer && NULL != peer->connections)
886 GNUNET_CONTAINER_multihashmap_remove (peer->connections, &c->id, c);
887
888 /* Delete */
889 GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO);
890 GNUNET_CONTAINER_DLL_remove (c->t->connection_head, c->t->connection_tail, c);
891 GNUNET_free (c);
892}
893
894
895
896/**
897 * Send an ACK informing the predecessor about the available buffer space.
898 *
899 * Note that for fwd ack, the FWD mean forward *traffic* (root->dest),
900 * the ACK itself goes "back" (dest->root).
901 *
902 * @param c Connection on which to send the ACK.
903 * @param buffer How much space free to advertise?
904 * @param fwd Is this FWD ACK? (Going dest->owner)
905 */
906static void
907connection_send_ack (struct MeshConnection *c, unsigned int buffer, int fwd)
908{
909 struct MeshFlowControl *next_fc;
910 struct MeshFlowControl *prev_fc;
911 struct GNUNET_MESH_ACK msg;
912 uint32_t ack;
913 int delta;
914
915 next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
916 prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
917
918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
919 "connection send %s ack on %s\n",
920 fwd ? "FWD" : "BCK", GNUNET_h2s (&c->id));
921
922 /* Check if we need to transmit the ACK */
923 if (prev_fc->last_ack_sent - prev_fc->last_pid_recv > 3)
924 {
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer > 3\n");
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927 " last pid recv: %u, last ack sent: %u\n",
928 prev_fc->last_pid_recv, prev_fc->last_ack_sent);
929 return;
930 }
931
932 /* Ok, ACK might be necessary, what PID to ACK? */
933 delta = next_fc->queue_max - next_fc->queue_n;
934 ack = prev_fc->last_pid_recv + delta;
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ACK %u\n", ack);
936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937 " last pid %u, last ack %u, qmax %u, q %u\n",
938 prev_fc->last_pid_recv, prev_fc->last_ack_sent,
939 next_fc->queue_max, next_fc->queue_n);
940 if (ack == prev_fc->last_ack_sent)
941 {
942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
943 return;
944 }
945
946 prev_fc->last_ack_sent = ack;
947
948 /* Build ACK message and send on connection */
949 msg.header.size = htons (sizeof (msg));
950 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_ACK);
951 msg.ack = htonl (ack);
952 msg.cid = c->id;
953
954 send_prebuilt_message_connection (&msg.header, c, NULL, !fwd);
955}
956
957
958static void
959connection_change_state (struct MeshConnection* c,
960 enum MeshConnectionState state)
961{
962 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
963 "Connection %s state was %s\n",
964 GNUNET_h2s (&c->id), GNUNET_MESH_DEBUG_CS2S (c->state));
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "Connection %s state is now %s\n",
967 GNUNET_h2s (&c->id), GNUNET_MESH_DEBUG_CS2S (state));
968 c->state = state;
969}
970
971
972
973/**
974 * Send keepalive packets for a connection.
975 *
976 * @param c Connection to keep alive..
977 * @param fwd Is this a FWD keepalive? (owner -> dest).
978 */
979static void
980connection_keepalive (struct MeshConnection *c, int fwd)
981{
982 struct GNUNET_MESH_ConnectionKeepAlive *msg;
983 size_t size = sizeof (struct GNUNET_MESH_ConnectionKeepAlive);
984 char cbuf[size];
985 uint16_t type;
986
987 type = fwd ? GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE :
988 GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE;
989
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "sending %s keepalive for connection %s[%d]\n",
992 fwd ? "FWD" : "BCK",
993 peer2s (c->t->peer),
994 c->id);
995
996 msg = (struct GNUNET_MESH_ConnectionKeepAlive *) cbuf;
997 msg->header.size = htons (size);
998 msg->header.type = htons (type);
999 msg->cid = c->id;
1000
1001 send_prebuilt_message_connection (&msg->header, c, NULL, fwd);
1002}
1003
1004
1005/**
1006 * Send CONNECTION_{CREATE/ACK} packets for a connection.
1007 *
1008 * @param c Connection for which to send the message.
1009 * @param fwd If GNUNET_YES, send CREATE, otherwise send ACK.
1010 */
1011static void
1012connection_recreate (struct MeshConnection *c, int fwd)
1013{
1014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending connection recreate\n");
1015 if (fwd)
1016 send_connection_create (c);
1017 else
1018 send_connection_ack (c, GNUNET_NO);
1019}
1020
1021
1022/**
1023 * Generic connection timer management.
1024 * Depending on the role of the peer in the connection will send the
1025 * appropriate message (build or keepalive)
1026 *
1027 * @param c Conncetion to maintain.
1028 * @param fwd Is FWD?
1029 */
1030static void
1031connection_maintain (struct MeshConnection *c, int fwd)
1032{
1033 if (MESH_TUNNEL_SEARCHING == c->t->state)
1034 {
1035 /* TODO DHT GET with RO_BART */
1036 return;
1037 }
1038 switch (c->state)
1039 {
1040 case MESH_CONNECTION_NEW:
1041 GNUNET_break (0);
1042 case MESH_CONNECTION_SENT:
1043 connection_recreate (c, fwd);
1044 break;
1045 case MESH_CONNECTION_READY:
1046 connection_keepalive (c, fwd);
1047 break;
1048 default:
1049 break;
1050 }
1051}
1052
1053
1054static void
1055connection_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1056{
1057 struct MeshConnection *c = cls;
1058
1059 c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
1060 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1061 return;
1062
1063 connection_maintain (c, GNUNET_YES);
1064 c->fwd_maintenance_task = GNUNET_SCHEDULER_add_delayed (refresh_connection_time,
1065 &connection_fwd_keepalive,
1066 c);
1067}
1068
1069
1070static void
1071connection_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1072{
1073 struct MeshConnection *c = cls;
1074
1075 c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
1076 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1077 return;
1078
1079 connection_maintain (c, GNUNET_NO);
1080 c->bck_maintenance_task = GNUNET_SCHEDULER_add_delayed (refresh_connection_time,
1081 &connection_bck_keepalive,
1082 c);
1083}
1084
1085
1086/**
1087 * Send a message to all peers in this connection that the connection
1088 * is no longer valid.
1089 *
1090 * If some peer should not receive the message, it should be zero'ed out
1091 * before calling this function.
1092 *
1093 * @param c The connection whose peers to notify.
1094 */
1095static void
1096connection_send_destroy (struct MeshConnection *c)
1097{
1098 struct GNUNET_MESH_ConnectionDestroy msg;
1099
1100 msg.header.size = htons (sizeof (msg));
1101 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY);;
1102 msg.cid = c->id;
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 " sending connection destroy for connection %s[%X]\n",
1105 peer2s (c->t->peer),
1106 c->id);
1107
1108 if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES))
1109 send_prebuilt_message_connection (&msg.header, c, NULL, GNUNET_YES);
1110 if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO))
1111 send_prebuilt_message_connection (&msg.header, c, NULL, GNUNET_NO);
1112 c->destroy = GNUNET_YES;
1113}
1114
1115
1116/**
1117 * Get free buffer space in a connection.
1118 *
1119 * @param c Connection.
1120 * @param fwd Is query about FWD traffic?
1121 *
1122 * @return Free buffer space [0 - max_msgs_queue/max_connections]
1123 */
1124static unsigned int
1125connection_get_buffer (struct MeshConnection *c, int fwd)
1126{
1127 struct MeshFlowControl *fc;
1128
1129 fc = fwd ? &c->fwd_fc : &c->bck_fc;
1130
1131 return (fc->queue_max - fc->queue_n);
1132}
1133
1134
1135/**
1136 * Get the first transmittable message for a connection.
1137 *
1138 * @param c Connection.
1139 * @param fwd Is this FWD?
1140 *
1141 * @return First transmittable message.
1142 */
1143static struct MeshPeerQueue *
1144connection_get_first_message (struct MeshConnection *c, int fwd)
1145{
1146 struct MeshPeerQueue *q;
1147 struct MeshPeer *p;
1148
1149 p = connection_get_hop (c, fwd);
1150
1151 for (q = p->queue_head; NULL != q; q = q->next)
1152 {
1153 if (q->c != c)
1154 continue;
1155 if (queue_is_sendable (q))
1156 return q;
1157 }
1158
1159 return NULL;
1160}
1161
1162
1163/**
1164 * @brief Re-initiate traffic on this connection if necessary.
1165 *
1166 * Check if there is traffic queued towards this peer
1167 * and the core transmit handle is NULL (traffic was stalled).
1168 * If so, call core tmt rdy.
1169 *
1170 * @param c Connection on which initiate traffic.
1171 * @param fwd Is this about fwd traffic?
1172 */
1173static void
1174connection_unlock_queue (struct MeshConnection *c, int fwd)
1175{
1176 struct MeshPeer *peer;
1177 struct MeshPeerQueue *q;
1178 size_t size;
1179
1180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1181 "connection_unlock_queue %s on %s\n",
1182 fwd ? "FWD" : "BCK", GNUNET_h2s (&c->id));
1183
1184 if (GMC_is_terminal (c, fwd))
1185 {
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " is terminal!\n");
1187 return;
1188 }
1189
1190 peer = connection_get_hop (c, fwd);
1191
1192 if (NULL != peer->core_transmit)
1193 {
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n");
1195 return; /* Already unlocked */
1196 }
1197
1198 q = connection_get_first_message (c, fwd);
1199 if (NULL == q)
1200 {
1201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n");
1202 return; /* Nothing to transmit */
1203 }
1204
1205 size = q->size;
1206 peer->core_transmit =
1207 GNUNET_CORE_notify_transmit_ready (core_handle,
1208 GNUNET_NO,
1209 0,
1210 GNUNET_TIME_UNIT_FOREVER_REL,
1211 GNUNET_PEER_resolve2 (peer->id),
1212 size,
1213 &queue_send,
1214 peer);
1215}
1216
1217
1218/**
1219 * Cancel all transmissions that belong to a certain connection.
1220 *
1221 * @param c Connection which to cancel.
1222 * @param fwd Cancel fwd traffic?
1223 */
1224static void
1225connection_cancel_queues (struct MeshConnection *c, int fwd)
1226{
1227 struct MeshPeerQueue *q;
1228 struct MeshPeerQueue *next;
1229 struct MeshFlowControl *fc;
1230 struct MeshPeer *peer;
1231
1232 if (NULL == c)
1233 {
1234 GNUNET_break (0);
1235 return;
1236 }
1237 fc = fwd ? &c->fwd_fc : &c->bck_fc;
1238 peer = connection_get_hop (c, fwd);
1239
1240 for (q = peer->queue_head; NULL != q; q = next)
1241 {
1242 next = q->next;
1243 if (q->c == c)
1244 {
1245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1246 "connection_cancel_queue %s\n",
1247 GNUNET_MESH_DEBUG_M2S (q->type));
1248 queue_destroy (q, GNUNET_YES);
1249 }
1250 }
1251 if (NULL == peer->queue_head)
1252 {
1253 if (NULL != peer->core_transmit)
1254 {
1255 GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
1256 peer->core_transmit = NULL;
1257 }
1258 if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task)
1259 {
1260 GNUNET_SCHEDULER_cancel (fc->poll_task);
1261 fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
1262 }
1263 }
1264}
1265
1266
1267
1268
1269/**
1270 * Function called if a connection has been stalled for a while,
1271 * possibly due to a missed ACK. Poll the neighbor about its ACK status.
1272 *
1273 * @param cls Closure (poll ctx).
1274 * @param tc TaskContext.
1275 */
1276static void
1277connection_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1278{
1279 struct MeshFlowControl *fc = cls;
1280 struct GNUNET_MESH_Poll msg;
1281 struct MeshConnection *c;
1282
1283 fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
1284 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1285 {
1286 return;
1287 }
1288
1289 c = fc->c;
1290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** Polling!\n");
1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** connection [%X]\n",
1292 GNUNET_h2s (&c->id));
1293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** %s\n",
1294 fc == &c->fwd_fc ? "FWD" : "BCK");
1295
1296 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_POLL);
1297 msg.header.size = htons (sizeof (msg));
1298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " *** pid (%u)!\n", fc->last_pid_sent);
1299 send_prebuilt_message_connection (&msg.header, c, NULL, fc == &c->fwd_fc);
1300 fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
1301 fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
1302 &connection_poll, fc);
1303}
1304
1305
1306
1307
1308/**
1309 * Get the previous hop in a connection
1310 *
1311 * @param c Connection.
1312 *
1313 * @return Previous peer in the connection.
1314 */
1315static struct MeshPeer *
1316connection_get_prev_hop (struct MeshConnection *c)
1317{
1318 GNUNET_PEER_Id id;
1319
1320 if (0 == c->own_pos || c->path->length < 2)
1321 id = c->path->peers[0];
1322 else
1323 id = c->path->peers[c->own_pos - 1];
1324
1325 return peer_get_short (id);
1326}
1327
1328
1329/**
1330 * Get the next hop in a connection
1331 *
1332 * @param c Connection.
1333 *
1334 * @return Next peer in the connection.
1335 */
1336static struct MeshPeer *
1337connection_get_next_hop (struct MeshConnection *c)
1338{
1339 GNUNET_PEER_Id id;
1340
1341 if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
1342 id = c->path->peers[c->path->length - 1];
1343 else
1344 id = c->path->peers[c->own_pos + 1];
1345
1346 return peer_get_short (id);
1347}
1348
1349
1350/**
1351 * Get the hop in a connection.
1352 *
1353 * @param c Connection.
1354 * @param fwd Next hop?
1355 *
1356 * @return Next peer in the connection.
1357 */
1358static struct MeshPeer *
1359connection_get_hop (struct MeshConnection *c, int fwd)
1360{
1361 if (fwd)
1362 return connection_get_next_hop (c);
1363 return connection_get_prev_hop (c);
1364}
1365
1366
1367
1368
1369/**
1370 * Timeout function due to lack of keepalive/traffic from the owner.
1371 * Destroys connection if called.
1372 *
1373 * @param cls Closure (connection to destroy).
1374 * @param tc TaskContext.
1375 */
1376static void
1377connection_fwd_timeout (void *cls,
1378 const struct GNUNET_SCHEDULER_TaskContext *tc)
1379{
1380 struct MeshConnection *c = cls;
1381
1382 c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
1383 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1384 return;
1385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386 "Connection %s[%X] FWD timed out. Destroying.\n",
1387 peer2s (c->t->peer),
1388 c->id);
1389
1390 if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */
1391 return;
1392
1393 GMC_destroy (c);
1394}
1395
1396
1397/**
1398 * Timeout function due to lack of keepalive/traffic from the destination.
1399 * Destroys connection if called.
1400 *
1401 * @param cls Closure (connection to destroy).
1402 * @param tc TaskContext
1403 */
1404static void
1405connection_bck_timeout (void *cls,
1406 const struct GNUNET_SCHEDULER_TaskContext *tc)
1407{
1408 struct MeshConnection *c = cls;
1409
1410 c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
1411 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1412 return;
1413
1414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1415 "Connection %s[%X] FWD timed out. Destroying.\n",
1416 peer2s (c->t->peer),
1417 c->id);
1418
1419 if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */
1420 return;
1421
1422 GMC_destroy (c);
1423}
1424
1425
1426/**
1427 * Resets the connection timeout task, some other message has done the
1428 * task's job.
1429 * - For the first peer on the direction this means to send
1430 * a keepalive or a path confirmation message (either create or ACK).
1431 * - For all other peers, this means to destroy the connection,
1432 * due to lack of activity.
1433 * Starts the tiemout if no timeout was running (connection just created).
1434 *
1435 * @param c Connection whose timeout to reset.
1436 * @param fwd Is this forward?
1437 *
1438 * TODO use heap to improve efficiency of scheduler.
1439 */
1440static void
1441connection_reset_timeout (struct MeshConnection *c, int fwd)
1442{
1443 GNUNET_SCHEDULER_TaskIdentifier *ti;
1444 GNUNET_SCHEDULER_Task f;
1445
1446 ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
1447
1448 if (GNUNET_SCHEDULER_NO_TASK != *ti)
1449 GNUNET_SCHEDULER_cancel (*ti);
1450
1451 if (GMC_is_origin (c, fwd)) /* Endpoint */
1452 {
1453 f = fwd ? &connection_fwd_keepalive : &connection_bck_keepalive;
1454 *ti = GNUNET_SCHEDULER_add_delayed (refresh_connection_time, f, c);
1455 }
1456 else /* Relay */
1457 {
1458 struct GNUNET_TIME_Relative delay;
1459
1460 delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4);
1461 f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
1462 *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
1463 }
1464}
1465
1466
1467/**
1468 * Iterator to notify all connections of a broken link. Mark connections
1469 * to destroy after all traffic has been sent.
1470 *
1471 * @param cls Closure (peer disconnected).
1472 * @param key Current key code (tid).
1473 * @param value Value in the hash map (connection).
1474 *
1475 * @return GNUNET_YES if we should continue to iterate,
1476 * GNUNET_NO if not.
1477 */
1478int
1479GMC_notify_broken (void *cls,
1480 const struct GNUNET_HashCode *key,
1481 void *value)
1482{
1483 struct MeshPeer *peer = cls;
1484 struct MeshConnection *c = value;
1485 struct GNUNET_MESH_ConnectionBroken msg;
1486 int fwd;
1487
1488 fwd = peer == connection_get_prev_hop (c);
1489
1490 connection_cancel_queues (c, !fwd);
1491 if (GMC_is_terminal (c, fwd))
1492 {
1493 /* Local shutdown, no one to notify about this. */
1494 GMC_destroy (c);
1495 return GNUNET_YES;
1496 }
1497
1498 msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectionBroken));
1499 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN);
1500 msg.cid = c->id;
1501 msg.peer1 = my_full_id;
1502 msg.peer2 = *GNUNET_PEER_resolve2 (peer->id);
1503 send_prebuilt_message_connection (&msg.header, c, NULL, fwd);
1504 c->destroy = GNUNET_YES;
1505
1506 return GNUNET_YES;
1507}
1508
1509
1510/**
1511 * Initialize the connections subsystem
1512 *
1513 * @param c Configuration handle.
1514 */
1515void
1516GMC_init (struct GNUNET_CONFIGURATION_Handle *c)
1517{
1518 if (GNUNET_OK !=
1519 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_MSGS_QUEUE",
1520 &max_msgs_queue))
1521 {
1522 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1523 "MESH", "MAX_MSGS_QUEUE", "MISSING");
1524 GNUNET_SCHEDULER_shutdown ();
1525 return;
1526 }
1527
1528 if (GNUNET_OK !=
1529 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_CONNECTIONS",
1530 &max_connections))
1531 {
1532 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1533 "MESH", "MAX_CONNECTIONS", "MISSING");
1534 GNUNET_SCHEDULER_shutdown ();
1535 return;
1536 }
1537
1538 if (GNUNET_OK !=
1539 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "REFRESH_CONNECTION_TIME",
1540 &refresh_connection_time))
1541 {
1542 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1543 "MESH", "REFRESH_CONNECTION_TIME", "MISSING");
1544 GNUNET_SCHEDULER_shutdown ();
1545 return;
1546 }
1547 connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
1548}
1549
1550
1551/**
1552 * Is this peer the first one on the connection?
1553 *
1554 * @param c Connection.
1555 * @param fwd Is this about fwd traffic?
1556 *
1557 * @return GNUNET_YES if origin, GNUNET_NO if relay/terminal.
1558 */
1559int
1560GMC_is_origin (struct MeshConnection *c, int fwd)
1561{
1562 if (!fwd && c->path->length - 1 == c->own_pos )
1563 return GNUNET_YES;
1564 if (fwd && 0 == c->own_pos)
1565 return GNUNET_YES;
1566 return GNUNET_NO;
1567}
1568
1569
1570/**
1571 * Is this peer the last one on the connection?
1572 *
1573 * @param c Connection.
1574 * @param fwd Is this about fwd traffic?
1575 * Note that the ROOT is the terminal for BCK traffic!
1576 *
1577 * @return GNUNET_YES if terminal, GNUNET_NO if relay/origin.
1578 */
1579int
1580GMC_is_terminal (struct MeshConnection *c, int fwd)
1581{
1582 return GMC_is_origin (c, !fwd);
1583} \ No newline at end of file