diff options
author | Bart Polot <bart@net.in.tum.de> | 2013-10-01 11:05:12 +0000 |
---|---|---|
committer | Bart Polot <bart@net.in.tum.de> | 2013-10-01 11:05:12 +0000 |
commit | 6e0d1b08237cba5ce900a95f231cb0164ff3606f (patch) | |
tree | 60874299ba0be683c7ad515137b29d743a9054e9 /src/mesh/gnunet-service-mesh_connection.c | |
parent | 941a901163d150d701e12d9b0b85cbb582c114b6 (diff) | |
download | gnunet-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.c | 1583 |
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 | */ | ||
37 | enum 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 | */ | ||
65 | struct 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 | */ | ||
118 | struct 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 | */ | ||
175 | struct 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 | */ | ||
249 | static 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 | */ | ||
255 | static 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 | */ | ||
261 | static unsigned long long max_msgs_queue; | ||
262 | |||
263 | /** | ||
264 | * How often to send path keepalives. Paths timeout after 4 missed. | ||
265 | */ | ||
266 | static 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 | */ | ||
276 | static void | ||
277 | fc_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 | */ | ||
296 | static struct MeshConnection * | ||
297 | connection_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 | */ | ||
310 | static struct MeshPeerQueue * | ||
311 | peer_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 | |||
325 | static int | ||
326 | queue_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 | */ | ||
355 | static void | ||
356 | queue_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 | |||
419 | static size_t | ||
420 | queue_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 | |||
611 | static void | ||
612 | queue_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 | */ | ||
755 | static void | ||
756 | send_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 | |||
840 | struct MeshConnection * | ||
841 | GMC_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 | |||
858 | static void | ||
859 | GMC_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 | */ | ||
906 | static void | ||
907 | connection_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 | |||
958 | static void | ||
959 | connection_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 | */ | ||
979 | static void | ||
980 | connection_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 | */ | ||
1011 | static void | ||
1012 | connection_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 | */ | ||
1030 | static void | ||
1031 | connection_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 | |||
1054 | static void | ||
1055 | connection_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 | |||
1070 | static void | ||
1071 | connection_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 | */ | ||
1095 | static void | ||
1096 | connection_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 | */ | ||
1124 | static unsigned int | ||
1125 | connection_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 | */ | ||
1143 | static struct MeshPeerQueue * | ||
1144 | connection_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 | */ | ||
1173 | static void | ||
1174 | connection_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 | */ | ||
1224 | static void | ||
1225 | connection_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 | */ | ||
1276 | static void | ||
1277 | connection_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 | */ | ||
1315 | static struct MeshPeer * | ||
1316 | connection_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 | */ | ||
1336 | static struct MeshPeer * | ||
1337 | connection_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 | */ | ||
1358 | static struct MeshPeer * | ||
1359 | connection_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 | */ | ||
1376 | static void | ||
1377 | connection_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 | */ | ||
1404 | static void | ||
1405 | connection_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 | */ | ||
1440 | static void | ||
1441 | connection_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 | */ | ||
1478 | int | ||
1479 | GMC_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 | */ | ||
1515 | void | ||
1516 | GMC_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 | */ | ||
1559 | int | ||
1560 | GMC_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 | */ | ||
1579 | int | ||
1580 | GMC_is_terminal (struct MeshConnection *c, int fwd) | ||
1581 | { | ||
1582 | return GMC_is_origin (c, !fwd); | ||
1583 | } \ No newline at end of file | ||