aboutsummaryrefslogtreecommitdiff
path: root/src/dv
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-12-10 12:50:34 +0000
committerChristian Grothoff <christian@grothoff.org>2013-12-10 12:50:34 +0000
commit83a5390a77b297df2ed9552be5cf7f6f8b15937f (patch)
treecf49e1e466d25ba2d845642b00b6c3666c913903 /src/dv
parent2a1341df0cf9c2ee085201ded0ae76c3fcb33de2 (diff)
downloadgnunet-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.c249
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 */
40struct ConnectedPeer;
41
42
43/**
38 * Handle for a send operation. 44 * Handle for a send operation.
39 */ 45 */
40struct GNUNET_DV_TransmitHandle 46struct 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 */
94struct 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 */
88struct GNUNET_DV_ServiceHandle 124struct 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 */
173static size_t 208static size_t
174transmit_pending (void *cls, size_t size, void *buf) 209transmit_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.
237struct 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 */
260static int 278static int
261process_ack (void *cls, 279cleanup_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 */
442static int
443cleanup_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 */
579struct GNUNET_DV_TransmitHandle * 619struct 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
635GNUNET_DV_send_cancel (struct GNUNET_DV_TransmitHandle *th) 682GNUNET_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);