diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-12-10 12:50:34 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-12-10 12:50:34 +0000 |
commit | 83a5390a77b297df2ed9552be5cf7f6f8b15937f (patch) | |
tree | cf49e1e466d25ba2d845642b00b6c3666c913903 /src/dv | |
parent | 2a1341df0cf9c2ee085201ded0ae76c3fcb33de2 (diff) | |
download | gnunet-83a5390a77b297df2ed9552be5cf7f6f8b15937f.tar.gz gnunet-83a5390a77b297df2ed9552be5cf7f6f8b15937f.zip |
-fixing #3181: close all connections on DV service reconnect, also track active connections and check that transmission requests are valid
Diffstat (limited to 'src/dv')
-rw-r--r-- | src/dv/dv_api.c | 249 |
1 files changed, 148 insertions, 101 deletions
diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c index 2c2953de2..eb86b7aec 100644 --- a/src/dv/dv_api.c +++ b/src/dv/dv_api.c | |||
@@ -35,6 +35,12 @@ | |||
35 | 35 | ||
36 | 36 | ||
37 | /** | 37 | /** |
38 | * Information we track for each peer. | ||
39 | */ | ||
40 | struct ConnectedPeer; | ||
41 | |||
42 | |||
43 | /** | ||
38 | * Handle for a send operation. | 44 | * Handle for a send operation. |
39 | */ | 45 | */ |
40 | struct GNUNET_DV_TransmitHandle | 46 | struct GNUNET_DV_TransmitHandle |
@@ -60,7 +66,7 @@ struct GNUNET_DV_TransmitHandle | |||
60 | GNUNET_DV_MessageSentCallback cb; | 66 | GNUNET_DV_MessageSentCallback cb; |
61 | 67 | ||
62 | /** | 68 | /** |
63 | * Closure for 'cb'. | 69 | * Closure for @a cb. |
64 | */ | 70 | */ |
65 | void *cb_cls; | 71 | void *cb_cls; |
66 | 72 | ||
@@ -72,7 +78,7 @@ struct GNUNET_DV_TransmitHandle | |||
72 | /** | 78 | /** |
73 | * Destination for the message. | 79 | * Destination for the message. |
74 | */ | 80 | */ |
75 | struct GNUNET_PeerIdentity target; | 81 | struct ConnectedPeer *target; |
76 | 82 | ||
77 | /** | 83 | /** |
78 | * UID of our message, if any. | 84 | * UID of our message, if any. |
@@ -83,6 +89,36 @@ struct GNUNET_DV_TransmitHandle | |||
83 | 89 | ||
84 | 90 | ||
85 | /** | 91 | /** |
92 | * Information we track for each peer. | ||
93 | */ | ||
94 | struct ConnectedPeer | ||
95 | { | ||
96 | |||
97 | /** | ||
98 | * Identity of the peer. | ||
99 | */ | ||
100 | struct GNUNET_PeerIdentity pid; | ||
101 | |||
102 | /** | ||
103 | * Head of DLL of transmission handles where we need | ||
104 | * to invoke a continuation when we are informed about | ||
105 | * successful transmission. The respective request | ||
106 | * has already been sent to the DV service. | ||
107 | */ | ||
108 | struct GNUNET_DV_TransmitHandle *head; | ||
109 | |||
110 | /** | ||
111 | * Tail of DLL of transmission handles where we need | ||
112 | * to invoke a continuation when we are informed about | ||
113 | * successful transmission. The respective request | ||
114 | * has already been sent to the DV service. | ||
115 | */ | ||
116 | struct GNUNET_DV_TransmitHandle *tail; | ||
117 | |||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
86 | * Handle to the DV service. | 122 | * Handle to the DV service. |
87 | */ | 123 | */ |
88 | struct GNUNET_DV_ServiceHandle | 124 | struct GNUNET_DV_ServiceHandle |
@@ -139,11 +175,10 @@ struct GNUNET_DV_ServiceHandle | |||
139 | struct GNUNET_DV_TransmitHandle *th_tail; | 175 | struct GNUNET_DV_TransmitHandle *th_tail; |
140 | 176 | ||
141 | /** | 177 | /** |
142 | * Mapping of peer identities to TransmitHandles to invoke | 178 | * Information tracked per connected peer. Maps peer |
143 | * upon successful transmission. The respective | 179 | * identities to `struct ConnectedPeer` entries. |
144 | * transmissions have already been done. | ||
145 | */ | 180 | */ |
146 | struct GNUNET_CONTAINER_MultiPeerMap *send_callbacks; | 181 | struct GNUNET_CONTAINER_MultiPeerMap *peers; |
147 | 182 | ||
148 | /** | 183 | /** |
149 | * Current unique ID | 184 | * Current unique ID |
@@ -168,7 +203,7 @@ reconnect (struct GNUNET_DV_ServiceHandle *sh); | |||
168 | * @param cls handle to the dv service (struct GNUNET_DV_ServiceHandle) | 203 | * @param cls handle to the dv service (struct GNUNET_DV_ServiceHandle) |
169 | * @param size how many bytes can we send | 204 | * @param size how many bytes can we send |
170 | * @param buf where to copy the message to send | 205 | * @param buf where to copy the message to send |
171 | * @return how many bytes we copied to buf | 206 | * @return how many bytes we copied to @a buf |
172 | */ | 207 | */ |
173 | static size_t | 208 | static size_t |
174 | transmit_pending (void *cls, size_t size, void *buf) | 209 | transmit_pending (void *cls, size_t size, void *buf) |
@@ -193,13 +228,13 @@ transmit_pending (void *cls, size_t size, void *buf) | |||
193 | sh->th_tail, | 228 | sh->th_tail, |
194 | th); | 229 | th); |
195 | memcpy (&cbuf[ret], th->msg, tsize); | 230 | memcpy (&cbuf[ret], th->msg, tsize); |
231 | th->msg = NULL; | ||
196 | ret += tsize; | 232 | ret += tsize; |
197 | if (NULL != th->cb) | 233 | if (NULL != th->cb) |
198 | { | 234 | { |
199 | (void) GNUNET_CONTAINER_multipeermap_put (sh->send_callbacks, | 235 | GNUNET_CONTAINER_DLL_insert (th->target->head, |
200 | &th->target, | 236 | th->target->tail, |
201 | th, | 237 | th); |
202 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
203 | } | 238 | } |
204 | else | 239 | else |
205 | { | 240 | { |
@@ -232,54 +267,36 @@ start_transmit (struct GNUNET_DV_ServiceHandle *sh) | |||
232 | 267 | ||
233 | 268 | ||
234 | /** | 269 | /** |
235 | * Closure for 'process_ack'. | 270 | * We got disconnected from the service and thus all of the |
236 | */ | 271 | * pending send callbacks will never be confirmed. Clean up. |
237 | struct AckContext | ||
238 | { | ||
239 | /** | ||
240 | * The ACK message. | ||
241 | */ | ||
242 | const struct GNUNET_DV_AckMessage *ack; | ||
243 | |||
244 | /** | ||
245 | * Our service handle. | ||
246 | */ | ||
247 | struct GNUNET_DV_ServiceHandle *sh; | ||
248 | }; | ||
249 | |||
250 | |||
251 | /** | ||
252 | * We got an ACK. Check if it matches the given transmit handle, and if | ||
253 | * so call the continuation. | ||
254 | * | 272 | * |
255 | * @param cls the 'struct AckContext' | 273 | * @param cls the 'struct GNUNET_DV_ServiceHandle' |
256 | * @param key peer identity | 274 | * @param key a peer identity |
257 | * @param value the 'struct GNUNET_DV_TransmitHandle' | 275 | * @param value a `struct ConnectedPeer` to clean up |
258 | * @return GNUNET_OK if the ACK did not match (continue to iterate) | 276 | * @return #GNUNET_OK (continue to iterate) |
259 | */ | 277 | */ |
260 | static int | 278 | static int |
261 | process_ack (void *cls, | 279 | cleanup_send_cb (void *cls, |
262 | const struct GNUNET_PeerIdentity *key, | 280 | const struct GNUNET_PeerIdentity *key, |
263 | void *value) | 281 | void *value) |
264 | { | 282 | { |
265 | struct AckContext *ctx = cls; | 283 | struct GNUNET_DV_ServiceHandle *sh = cls; |
266 | struct GNUNET_DV_TransmitHandle *th = value; | 284 | struct ConnectedPeer *peer = value; |
285 | struct GNUNET_DV_TransmitHandle *th; | ||
267 | 286 | ||
268 | if (th->uid != ntohl (ctx->ack->uid)) | ||
269 | return GNUNET_OK; | ||
270 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
271 | "Matchedk ACK for message to peer %s\n", | ||
272 | GNUNET_i2s (key)); | ||
273 | GNUNET_assert (GNUNET_YES == | 287 | GNUNET_assert (GNUNET_YES == |
274 | GNUNET_CONTAINER_multipeermap_remove (ctx->sh->send_callbacks, | 288 | GNUNET_CONTAINER_multipeermap_remove (sh->peers, |
275 | key, | 289 | key, |
276 | th)); | 290 | peer)); |
277 | th->cb (th->cb_cls, | 291 | sh->disconnect_cb (sh->cls, |
278 | (ntohs (ctx->ack->header.type) == GNUNET_MESSAGE_TYPE_DV_SEND_ACK) | 292 | key); |
279 | ? GNUNET_OK | 293 | while (NULL != (th = peer->head)) |
280 | : GNUNET_SYSERR); | 294 | { |
281 | GNUNET_free (th); | 295 | GNUNET_CONTAINER_DLL_remove (peer->head, peer->tail, th); |
282 | return GNUNET_NO; | 296 | th->cb (th->cb_cls, GNUNET_SYSERR); |
297 | GNUNET_free (th); | ||
298 | } | ||
299 | return GNUNET_OK; | ||
283 | } | 300 | } |
284 | 301 | ||
285 | 302 | ||
@@ -301,7 +318,9 @@ handle_message_receipt (void *cls, | |||
301 | const struct GNUNET_DV_ReceivedMessage *rm; | 318 | const struct GNUNET_DV_ReceivedMessage *rm; |
302 | const struct GNUNET_MessageHeader *payload; | 319 | const struct GNUNET_MessageHeader *payload; |
303 | const struct GNUNET_DV_AckMessage *ack; | 320 | const struct GNUNET_DV_AckMessage *ack; |
304 | struct AckContext ctx; | 321 | struct GNUNET_DV_TransmitHandle *th; |
322 | struct GNUNET_DV_TransmitHandle *tn; | ||
323 | struct ConnectedPeer *peer; | ||
305 | 324 | ||
306 | if (NULL == msg) | 325 | if (NULL == msg) |
307 | { | 326 | { |
@@ -322,6 +341,21 @@ handle_message_receipt (void *cls, | |||
322 | return; | 341 | return; |
323 | } | 342 | } |
324 | cm = (const struct GNUNET_DV_ConnectMessage *) msg; | 343 | cm = (const struct GNUNET_DV_ConnectMessage *) msg; |
344 | peer = GNUNET_CONTAINER_multipeermap_get (sh->peers, | ||
345 | &cm->peer); | ||
346 | if (NULL != peer) | ||
347 | { | ||
348 | GNUNET_break (0); | ||
349 | reconnect (sh); | ||
350 | return; | ||
351 | } | ||
352 | peer = GNUNET_new (struct ConnectedPeer); | ||
353 | peer->pid = cm->peer; | ||
354 | GNUNET_assert (GNUNET_OK == | ||
355 | GNUNET_CONTAINER_multipeermap_put (sh->peers, | ||
356 | &peer->pid, | ||
357 | peer, | ||
358 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
325 | sh->connect_cb (sh->cls, | 359 | sh->connect_cb (sh->cls, |
326 | &cm->peer, | 360 | &cm->peer, |
327 | ntohl (cm->distance), ntohl (cm->network)); | 361 | ntohl (cm->distance), ntohl (cm->network)); |
@@ -346,8 +380,28 @@ handle_message_receipt (void *cls, | |||
346 | return; | 380 | return; |
347 | } | 381 | } |
348 | dm = (const struct GNUNET_DV_DisconnectMessage *) msg; | 382 | dm = (const struct GNUNET_DV_DisconnectMessage *) msg; |
349 | sh->disconnect_cb (sh->cls, | 383 | peer = GNUNET_CONTAINER_multipeermap_get (sh->peers, |
350 | &dm->peer); | 384 | &dm->peer); |
385 | if (NULL == peer) | ||
386 | { | ||
387 | GNUNET_break (0); | ||
388 | reconnect (sh); | ||
389 | return; | ||
390 | } | ||
391 | tn = sh->th_head; | ||
392 | while (NULL != (th = tn)) | ||
393 | { | ||
394 | tn = th->next; | ||
395 | if (peer == th->target) | ||
396 | { | ||
397 | GNUNET_CONTAINER_DLL_remove (sh->th_head, | ||
398 | sh->th_tail, | ||
399 | th); | ||
400 | th->cb (th->cb_cls, GNUNET_SYSERR); | ||
401 | GNUNET_free (th); | ||
402 | } | ||
403 | } | ||
404 | cleanup_send_cb (sh, &dm->peer, peer); | ||
351 | break; | 405 | break; |
352 | case GNUNET_MESSAGE_TYPE_DV_RECV: | 406 | case GNUNET_MESSAGE_TYPE_DV_RECV: |
353 | if (ntohs (msg->size) < sizeof (struct GNUNET_DV_ReceivedMessage) + sizeof (struct GNUNET_MessageHeader)) | 407 | if (ntohs (msg->size) < sizeof (struct GNUNET_DV_ReceivedMessage) + sizeof (struct GNUNET_MessageHeader)) |
@@ -378,12 +432,25 @@ handle_message_receipt (void *cls, | |||
378 | return; | 432 | return; |
379 | } | 433 | } |
380 | ack = (const struct GNUNET_DV_AckMessage *) msg; | 434 | ack = (const struct GNUNET_DV_AckMessage *) msg; |
381 | ctx.ack = ack; | 435 | peer = GNUNET_CONTAINER_multipeermap_get (sh->peers, |
382 | ctx.sh = sh; | 436 | &ack->target); |
383 | GNUNET_CONTAINER_multipeermap_get_multiple (sh->send_callbacks, | 437 | for (th = peer->head; NULL != th; th = th->next) |
384 | &ack->target, | 438 | { |
385 | &process_ack, | 439 | if (th->uid != ntohl (ack->uid)) |
386 | &ctx); | 440 | continue; |
441 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
442 | "Matched ACK for message to peer %s\n", | ||
443 | GNUNET_i2s (&ack->target)); | ||
444 | GNUNET_CONTAINER_DLL_remove (peer->head, | ||
445 | peer->tail, | ||
446 | th); | ||
447 | th->cb (th->cb_cls, | ||
448 | (ntohs (ack->header.type) == GNUNET_MESSAGE_TYPE_DV_SEND_ACK) | ||
449 | ? GNUNET_OK | ||
450 | : GNUNET_SYSERR); | ||
451 | GNUNET_free (th); | ||
452 | break; | ||
453 | } | ||
387 | break; | 454 | break; |
388 | default: | 455 | default: |
389 | reconnect (sh); | 456 | reconnect (sh); |
@@ -398,7 +465,7 @@ handle_message_receipt (void *cls, | |||
398 | /** | 465 | /** |
399 | * Transmit the start message to the DV service. | 466 | * Transmit the start message to the DV service. |
400 | * | 467 | * |
401 | * @param cls the 'struct GNUNET_DV_ServiceHandle' | 468 | * @param cls the `struct GNUNET_DV_ServiceHandle *` |
402 | * @param size number of bytes available in buf | 469 | * @param size number of bytes available in buf |
403 | * @param buf where to copy the message | 470 | * @param buf where to copy the message |
404 | * @return number of bytes written to buf | 471 | * @return number of bytes written to buf |
@@ -431,33 +498,6 @@ transmit_start (void *cls, | |||
431 | 498 | ||
432 | 499 | ||
433 | /** | 500 | /** |
434 | * We got disconnected from the service and thus all of the | ||
435 | * pending send callbacks will never be confirmed. Clean up. | ||
436 | * | ||
437 | * @param cls the 'struct GNUNET_DV_ServiceHandle' | ||
438 | * @param key a peer identity | ||
439 | * @param value a 'struct GNUNET_DV_TransmitHandle' to clean up | ||
440 | * @return GNUNET_OK (continue to iterate) | ||
441 | */ | ||
442 | static int | ||
443 | cleanup_send_cb (void *cls, | ||
444 | const struct GNUNET_PeerIdentity *key, | ||
445 | void *value) | ||
446 | { | ||
447 | struct GNUNET_DV_ServiceHandle *sh = cls; | ||
448 | struct GNUNET_DV_TransmitHandle *th = value; | ||
449 | |||
450 | GNUNET_assert (GNUNET_YES == | ||
451 | GNUNET_CONTAINER_multipeermap_remove (sh->send_callbacks, | ||
452 | key, | ||
453 | th)); | ||
454 | th->cb (th->cb_cls, GNUNET_SYSERR); | ||
455 | GNUNET_free (th); | ||
456 | return GNUNET_OK; | ||
457 | } | ||
458 | |||
459 | |||
460 | /** | ||
461 | * Disconnect and then reconnect to the DV service. | 501 | * Disconnect and then reconnect to the DV service. |
462 | * | 502 | * |
463 | * @param sh service handle | 503 | * @param sh service handle |
@@ -475,7 +515,7 @@ reconnect (struct GNUNET_DV_ServiceHandle *sh) | |||
475 | GNUNET_CLIENT_disconnect (sh->client); | 515 | GNUNET_CLIENT_disconnect (sh->client); |
476 | sh->client = NULL; | 516 | sh->client = NULL; |
477 | } | 517 | } |
478 | GNUNET_CONTAINER_multipeermap_iterate (sh->send_callbacks, | 518 | GNUNET_CONTAINER_multipeermap_iterate (sh->peers, |
479 | &cleanup_send_cb, | 519 | &cleanup_send_cb, |
480 | sh); | 520 | sh); |
481 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 521 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -523,7 +563,7 @@ GNUNET_DV_service_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
523 | sh->distance_cb = distance_cb; | 563 | sh->distance_cb = distance_cb; |
524 | sh->disconnect_cb = disconnect_cb; | 564 | sh->disconnect_cb = disconnect_cb; |
525 | sh->message_cb = message_cb; | 565 | sh->message_cb = message_cb; |
526 | sh->send_callbacks = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); | 566 | sh->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); |
527 | reconnect (sh); | 567 | reconnect (sh); |
528 | return sh; | 568 | return sh; |
529 | } | 569 | } |
@@ -558,10 +598,10 @@ GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh) | |||
558 | GNUNET_CLIENT_disconnect (sh->client); | 598 | GNUNET_CLIENT_disconnect (sh->client); |
559 | sh->client = NULL; | 599 | sh->client = NULL; |
560 | } | 600 | } |
561 | GNUNET_CONTAINER_multipeermap_iterate (sh->send_callbacks, | 601 | GNUNET_CONTAINER_multipeermap_iterate (sh->peers, |
562 | &cleanup_send_cb, | 602 | &cleanup_send_cb, |
563 | sh); | 603 | sh); |
564 | GNUNET_CONTAINER_multipeermap_destroy (sh->send_callbacks); | 604 | GNUNET_CONTAINER_multipeermap_destroy (sh->peers); |
565 | GNUNET_free (sh); | 605 | GNUNET_free (sh); |
566 | } | 606 | } |
567 | 607 | ||
@@ -573,7 +613,7 @@ GNUNET_DV_service_disconnect (struct GNUNET_DV_ServiceHandle *sh) | |||
573 | * @param target intended recpient | 613 | * @param target intended recpient |
574 | * @param msg message payload | 614 | * @param msg message payload |
575 | * @param cb function to invoke when done | 615 | * @param cb function to invoke when done |
576 | * @param cb_cls closure for 'cb' | 616 | * @param cb_cls closure for @a cb |
577 | * @return handle to cancel the operation | 617 | * @return handle to cancel the operation |
578 | */ | 618 | */ |
579 | struct GNUNET_DV_TransmitHandle * | 619 | struct GNUNET_DV_TransmitHandle * |
@@ -585,6 +625,7 @@ GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh, | |||
585 | { | 625 | { |
586 | struct GNUNET_DV_TransmitHandle *th; | 626 | struct GNUNET_DV_TransmitHandle *th; |
587 | struct GNUNET_DV_SendMessage *sm; | 627 | struct GNUNET_DV_SendMessage *sm; |
628 | struct ConnectedPeer *peer; | ||
588 | 629 | ||
589 | if (ntohs (msg->size) + sizeof (struct GNUNET_DV_SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | 630 | if (ntohs (msg->size) + sizeof (struct GNUNET_DV_SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) |
590 | { | 631 | { |
@@ -596,12 +637,18 @@ GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh, | |||
596 | (unsigned int) msg->size, | 637 | (unsigned int) msg->size, |
597 | (unsigned int) msg->type, | 638 | (unsigned int) msg->type, |
598 | GNUNET_i2s (target)); | 639 | GNUNET_i2s (target)); |
599 | 640 | peer = GNUNET_CONTAINER_multipeermap_get (sh->peers, | |
641 | target); | ||
642 | if (NULL == peer) | ||
643 | { | ||
644 | GNUNET_break (0); | ||
645 | return NULL; | ||
646 | } | ||
600 | th = GNUNET_malloc (sizeof (struct GNUNET_DV_TransmitHandle) + | 647 | th = GNUNET_malloc (sizeof (struct GNUNET_DV_TransmitHandle) + |
601 | sizeof (struct GNUNET_DV_SendMessage) + | 648 | sizeof (struct GNUNET_DV_SendMessage) + |
602 | ntohs (msg->size)); | 649 | ntohs (msg->size)); |
603 | th->sh = sh; | 650 | th->sh = sh; |
604 | th->target = *target; | 651 | th->target = peer; |
605 | th->cb = cb; | 652 | th->cb = cb; |
606 | th->cb_cls = cb_cls; | 653 | th->cb_cls = cb_cls; |
607 | th->msg = (const struct GNUNET_MessageHeader *) &th[1]; | 654 | th->msg = (const struct GNUNET_MessageHeader *) &th[1]; |
@@ -635,12 +682,12 @@ void | |||
635 | GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th) | 682 | GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th) |
636 | { | 683 | { |
637 | struct GNUNET_DV_ServiceHandle *sh = th->sh; | 684 | struct GNUNET_DV_ServiceHandle *sh = th->sh; |
638 | int ret; | ||
639 | 685 | ||
640 | ret = GNUNET_CONTAINER_multipeermap_remove (sh->send_callbacks, | 686 | if (NULL == th->msg) |
641 | &th->target, | 687 | GNUNET_CONTAINER_DLL_remove (th->target->head, |
642 | th); | 688 | th->target->tail, |
643 | if (GNUNET_YES != ret) | 689 | th); |
690 | else | ||
644 | GNUNET_CONTAINER_DLL_remove (sh->th_head, | 691 | GNUNET_CONTAINER_DLL_remove (sh->th_head, |
645 | sh->th_tail, | 692 | sh->th_tail, |
646 | th); | 693 | th); |