diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-01-26 12:27:50 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-01-26 12:27:50 +0100 |
commit | cb26df28be6f46898c34d7e8957baa86fa56ed11 (patch) | |
tree | 04fb4a82c0b3f823ff6c577efa10d36c74275b3e /src/transport | |
parent | d1a4a8f64bba3399d16b2717c67f00957963983b (diff) | |
download | gnunet-cb26df28be6f46898c34d7e8957baa86fa56ed11.tar.gz gnunet-cb26df28be6f46898c34d7e8957baa86fa56ed11.zip |
data structures for defragmentation
Diffstat (limited to 'src/transport')
-rw-r--r-- | src/transport/gnunet-service-tng.c | 623 |
1 files changed, 595 insertions, 28 deletions
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c index cb6fcebdc..ac4a262d7 100644 --- a/src/transport/gnunet-service-tng.c +++ b/src/transport/gnunet-service-tng.c | |||
@@ -33,8 +33,11 @@ | |||
33 | * transport-to-transport traffic) | 33 | * transport-to-transport traffic) |
34 | * | 34 | * |
35 | * Implement: | 35 | * Implement: |
36 | * - manage defragmentation, retransmission, track RTT, loss, etc. | 36 | * - data structures for defragmentation |
37 | * - DV data structures, learning, forgetting, using them! | 37 | * - manage defragmentation |
38 | * - ACK handling / retransmission | ||
39 | * - track RTT, distance, loss, etc. | ||
40 | * - DV data structures, learning, forgetting & using them! | ||
38 | * | 41 | * |
39 | * Easy: | 42 | * Easy: |
40 | * - use ATS bandwidth allocation callback and schedule transmissions! | 43 | * - use ATS bandwidth allocation callback and schedule transmissions! |
@@ -83,6 +86,7 @@ | |||
83 | #include "gnunet_peerstore_service.h" | 86 | #include "gnunet_peerstore_service.h" |
84 | #include "gnunet_hello_lib.h" | 87 | #include "gnunet_hello_lib.h" |
85 | #include "gnunet_ats_transport_service.h" | 88 | #include "gnunet_ats_transport_service.h" |
89 | #include "gnunet_signatures.h" | ||
86 | #include "transport.h" | 90 | #include "transport.h" |
87 | 91 | ||
88 | 92 | ||
@@ -100,6 +104,16 @@ | |||
100 | #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | 104 | #define DELAY_WARN_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) |
101 | 105 | ||
102 | /** | 106 | /** |
107 | * How long are ephemeral keys valid? | ||
108 | */ | ||
109 | #define EPHEMERAL_VALIDITY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) | ||
110 | |||
111 | /** | ||
112 | * How long do we keep partially reassembled messages around before giving up? | ||
113 | */ | ||
114 | #define REASSEMBLY_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4) | ||
115 | |||
116 | /** | ||
103 | * How many messages can we have pending for a given communicator | 117 | * How many messages can we have pending for a given communicator |
104 | * process before we start to throttle that communicator? | 118 | * process before we start to throttle that communicator? |
105 | * | 119 | * |
@@ -169,8 +183,7 @@ struct TransportBackchannelEncapsulationMessage | |||
169 | 183 | ||
170 | 184 | ||
171 | /** | 185 | /** |
172 | * Body by which a peqer confirms that it is using an ephemeral | 186 | * Body by which a peer confirms that it is using an ephemeral key. |
173 | * key. | ||
174 | */ | 187 | */ |
175 | struct EphemeralConfirmation | 188 | struct EphemeralConfirmation |
176 | { | 189 | { |
@@ -182,10 +195,24 @@ struct EphemeralConfirmation | |||
182 | 195 | ||
183 | /** | 196 | /** |
184 | * How long is this signature over the ephemeral key valid? | 197 | * How long is this signature over the ephemeral key valid? |
198 | * Note that the receiver MUST IGNORE the absolute time, and | ||
199 | * only interpret the value as a mononic time and reject | ||
200 | * "older" values than the last one observed. Even with this, | ||
201 | * there is no real guarantee against replay achieved here, | ||
202 | * as the latest timestamp is not persisted. This is | ||
203 | * necessary as we do not want to require synchronized | ||
204 | * clocks and may not have a bidirectional communication | ||
205 | * channel. Communicators must protect against replay | ||
206 | * attacks when using backchannel communication! | ||
185 | */ | 207 | */ |
186 | struct GNUNET_TIME_AbsoluteNBO ephemeral_validity; | 208 | struct GNUNET_TIME_AbsoluteNBO ephemeral_validity; |
187 | 209 | ||
188 | /** | 210 | /** |
211 | * Target's peer identity. | ||
212 | */ | ||
213 | struct GNUNET_PeerIdentity target; | ||
214 | |||
215 | /** | ||
189 | * Ephemeral key setup by the sender for @e target, used | 216 | * Ephemeral key setup by the sender for @e target, used |
190 | * to encrypt the payload. | 217 | * to encrypt the payload. |
191 | */ | 218 | */ |
@@ -376,6 +403,12 @@ struct TransportFragmentAckMessage | |||
376 | * average transmission time of the sender minus this value. | 403 | * average transmission time of the sender minus this value. |
377 | */ | 404 | */ |
378 | struct GNUNET_TIME_RelativeNBO avg_ack_delay; | 405 | struct GNUNET_TIME_RelativeNBO avg_ack_delay; |
406 | |||
407 | /** | ||
408 | * How long until the receiver will stop trying reassembly | ||
409 | * of this message? | ||
410 | */ | ||
411 | struct GNUNET_TIME_RelativeNBO reassembly_timeout; | ||
379 | }; | 412 | }; |
380 | 413 | ||
381 | 414 | ||
@@ -549,6 +582,11 @@ struct EphemeralCacheEntry | |||
549 | struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key; | 582 | struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key; |
550 | 583 | ||
551 | /** | 584 | /** |
585 | * Our private ephemeral key. | ||
586 | */ | ||
587 | struct GNUNET_CRYPTO_EcdhePrivateKey private_key; | ||
588 | |||
589 | /** | ||
552 | * Node in the ephemeral cache for this entry. | 590 | * Node in the ephemeral cache for this entry. |
553 | * Used for expiration. | 591 | * Used for expiration. |
554 | */ | 592 | */ |
@@ -727,6 +765,96 @@ struct GNUNET_ATS_Session | |||
727 | 765 | ||
728 | 766 | ||
729 | /** | 767 | /** |
768 | * Information we keep for a message that we are reassembling. | ||
769 | */ | ||
770 | struct ReassemblyContext | ||
771 | { | ||
772 | |||
773 | /** | ||
774 | * Original message ID for of the message that all the | ||
775 | * fragments belong to. | ||
776 | */ | ||
777 | struct GNUNET_ShortHashCode msg_uuid; | ||
778 | |||
779 | /** | ||
780 | * Which neighbour is this context for? | ||
781 | */ | ||
782 | struct Neighbour *neighbour; | ||
783 | |||
784 | /** | ||
785 | * Entry in the reassembly heap (sorted by expiration). | ||
786 | */ | ||
787 | struct GNUNET_CONTAINER_HeapNode *hn; | ||
788 | |||
789 | /** | ||
790 | * Bitfield with @e msg_size bits representing the positions | ||
791 | * where we have received fragments. When we receive a fragment, | ||
792 | * we check the bits in @e bitfield before incrementing @e msg_missing. | ||
793 | * | ||
794 | * Allocated after the reassembled message. | ||
795 | */ | ||
796 | uint8_t *bitfield; | ||
797 | |||
798 | /** | ||
799 | * Task for sending ACK. We may send ACKs either because of hitting | ||
800 | * the @e extra_acks limit, or based on time and @e num_acks. This | ||
801 | * task is for the latter case. | ||
802 | */ | ||
803 | struct GNUNET_SCHEDULER_Task *ack_task; | ||
804 | |||
805 | /** | ||
806 | * At what time will we give up reassembly of this message? | ||
807 | */ | ||
808 | struct GNUNET_TIME_Absolute reassembly_timeout; | ||
809 | |||
810 | /** | ||
811 | * Average delay of all acks in @e extra_acks and @e frag_uuid. | ||
812 | * Should be reset to zero when @e num_acks is set to 0. | ||
813 | */ | ||
814 | struct GNUNET_TIME_Relative avg_ack_delay; | ||
815 | |||
816 | /** | ||
817 | * Time we received the last fragment. @e avg_ack_delay must be | ||
818 | * incremented by now - @e last_frag multiplied by @e num_acks. | ||
819 | */ | ||
820 | struct GNUNET_TIME_Absolute last_frag; | ||
821 | |||
822 | /** | ||
823 | * Bitfield of up to 64 additional fragments following @e frag_uuid | ||
824 | * to be acknowledged in the next cummulative ACK. | ||
825 | */ | ||
826 | uint64_t extra_acks; | ||
827 | |||
828 | /** | ||
829 | * Unique ID of the lowest fragment UUID to be acknowledged in the | ||
830 | * next cummulative ACK. Only valid if @e num_acks > 0. | ||
831 | */ | ||
832 | uint32_t frag_uuid; | ||
833 | |||
834 | /** | ||
835 | * Number of ACKs we have accumulated so far. Reset to 0 | ||
836 | * whenever we send a #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT_ACK. | ||
837 | */ | ||
838 | unsigned int num_acks; | ||
839 | |||
840 | /** | ||
841 | * How big is the message we are reassembling in total? | ||
842 | */ | ||
843 | uint16_t msg_size; | ||
844 | |||
845 | /** | ||
846 | * How many bytes of the message are still missing? Defragmentation | ||
847 | * is complete when @e msg_missing == 0. | ||
848 | */ | ||
849 | uint16_t msg_missing; | ||
850 | |||
851 | /* Followed by @e msg_size bytes of the (partially) defragmented original message */ | ||
852 | |||
853 | /* Followed by @e bitfield data */ | ||
854 | }; | ||
855 | |||
856 | |||
857 | /** | ||
730 | * A neighbour that at least one communicator is connected to. | 858 | * A neighbour that at least one communicator is connected to. |
731 | */ | 859 | */ |
732 | struct Neighbour | 860 | struct Neighbour |
@@ -738,6 +866,25 @@ struct Neighbour | |||
738 | struct GNUNET_PeerIdentity pid; | 866 | struct GNUNET_PeerIdentity pid; |
739 | 867 | ||
740 | /** | 868 | /** |
869 | * Map with `struct ReassemblyContext` structs for fragments under | ||
870 | * reassembly. May be NULL if we currently have no fragments from | ||
871 | * this @e pid (lazy initialization). | ||
872 | */ | ||
873 | struct GNUNET_CONTAINER_MultiShortmap *reassembly_map; | ||
874 | |||
875 | /** | ||
876 | * Heap with `struct ReassemblyContext` structs for fragments under | ||
877 | * reassembly. May be NULL if we currently have no fragments from | ||
878 | * this @e pid (lazy initialization). | ||
879 | */ | ||
880 | struct GNUNET_CONTAINER_Heap *reassembly_heap; | ||
881 | |||
882 | /** | ||
883 | * Task to free old entries from the @e reassembly_heap and @e reassembly_map. | ||
884 | */ | ||
885 | struct GNUNET_SCHEDULER_Task *reassembly_timeout_task; | ||
886 | |||
887 | /** | ||
741 | * Head of list of messages pending for this neighbour. | 888 | * Head of list of messages pending for this neighbour. |
742 | */ | 889 | */ |
743 | struct PendingMessage *pending_msg_head; | 890 | struct PendingMessage *pending_msg_head; |
@@ -1178,6 +1325,11 @@ static struct GNUNET_CONTAINER_Heap *ephemeral_heap; | |||
1178 | static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map; | 1325 | static struct GNUNET_CONTAINER_MultiPeerMap *ephemeral_map; |
1179 | 1326 | ||
1180 | /** | 1327 | /** |
1328 | * Task to free expired ephemerals. | ||
1329 | */ | ||
1330 | static struct GNUNET_SCHEDULER_Task *ephemeral_task; | ||
1331 | |||
1332 | /** | ||
1181 | * Our connection to ATS for allocation and bootstrapping. | 1333 | * Our connection to ATS for allocation and bootstrapping. |
1182 | */ | 1334 | */ |
1183 | static struct GNUNET_ATS_TransportHandle *ats; | 1335 | static struct GNUNET_ATS_TransportHandle *ats; |
@@ -1364,6 +1516,76 @@ client_connect_cb (void *cls, | |||
1364 | 1516 | ||
1365 | 1517 | ||
1366 | /** | 1518 | /** |
1519 | * Free @a rc | ||
1520 | * | ||
1521 | * @param rc data structure to free | ||
1522 | */ | ||
1523 | static void | ||
1524 | free_reassembly_context (struct ReassemblyContext *rc) | ||
1525 | { | ||
1526 | struct Neighbour *n = rc->neighbour; | ||
1527 | |||
1528 | GNUNET_assert (rc == | ||
1529 | GNUNET_CONTAINER_heap_remove_node (rc->hn)); | ||
1530 | GNUNET_assert (GNUNET_OK == | ||
1531 | GNUNET_CONTAINER_multishortmap_remove (n->reassembly_map, | ||
1532 | &rc->msg_uuid, | ||
1533 | rc)); | ||
1534 | GNUNET_free (rc); | ||
1535 | } | ||
1536 | |||
1537 | |||
1538 | /** | ||
1539 | * Task run to clean up reassembly context of a neighbour that have expired. | ||
1540 | * | ||
1541 | * @param cls a `struct Neighbour` | ||
1542 | */ | ||
1543 | static void | ||
1544 | reassembly_cleanup_task (void *cls) | ||
1545 | { | ||
1546 | struct Neighbour *n = cls; | ||
1547 | struct ReassemblyContext *rc; | ||
1548 | |||
1549 | n->reassembly_timeout_task = NULL; | ||
1550 | while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap))) | ||
1551 | { | ||
1552 | if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout).rel_value_us) | ||
1553 | { | ||
1554 | free_reassembly_context (rc); | ||
1555 | continue; | ||
1556 | } | ||
1557 | GNUNET_assert (NULL == n->reassembly_timeout_task); | ||
1558 | n->reassembly_timeout_task = GNUNET_SCHEDULER_add_at (rc->reassembly_timeout, | ||
1559 | &reassembly_cleanup_task, | ||
1560 | n); | ||
1561 | return; | ||
1562 | } | ||
1563 | } | ||
1564 | |||
1565 | |||
1566 | /** | ||
1567 | * function called to #free_reassembly_context(). | ||
1568 | * | ||
1569 | * @param cls NULL | ||
1570 | * @param key unused | ||
1571 | * @param value a `struct ReassemblyContext` to free | ||
1572 | * @return #GNUNET_OK (continue iteration) | ||
1573 | */ | ||
1574 | static int | ||
1575 | free_reassembly_cb (void *cls, | ||
1576 | const struct GNUNET_ShortHashCode *key, | ||
1577 | void *value) | ||
1578 | { | ||
1579 | struct ReassemblyContext *rc = value; | ||
1580 | (void) cls; | ||
1581 | (void) key; | ||
1582 | |||
1583 | free_reassembly_context (rc); | ||
1584 | return GNUNET_OK; | ||
1585 | } | ||
1586 | |||
1587 | |||
1588 | /** | ||
1367 | * Release memory used by @a neighbour. | 1589 | * Release memory used by @a neighbour. |
1368 | * | 1590 | * |
1369 | * @param neighbour neighbour entry to free | 1591 | * @param neighbour neighbour entry to free |
@@ -1378,6 +1600,18 @@ free_neighbour (struct Neighbour *neighbour) | |||
1378 | neighbour)); | 1600 | neighbour)); |
1379 | if (NULL != neighbour->timeout_task) | 1601 | if (NULL != neighbour->timeout_task) |
1380 | GNUNET_SCHEDULER_cancel (neighbour->timeout_task); | 1602 | GNUNET_SCHEDULER_cancel (neighbour->timeout_task); |
1603 | if (NULL != neighbour->reassembly_map) | ||
1604 | { | ||
1605 | GNUNET_CONTAINER_multishortmap_iterate (neighbour->reassembly_map, | ||
1606 | &free_reassembly_cb, | ||
1607 | NULL); | ||
1608 | GNUNET_CONTAINER_multishortmap_destroy (neighbour->reassembly_map); | ||
1609 | neighbour->reassembly_map = NULL; | ||
1610 | GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap); | ||
1611 | neighbour->reassembly_heap = NULL; | ||
1612 | } | ||
1613 | if (NULL != neighbour->reassembly_timeout_task) | ||
1614 | GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task); | ||
1381 | GNUNET_free (neighbour); | 1615 | GNUNET_free (neighbour); |
1382 | } | 1616 | } |
1383 | 1617 | ||
@@ -2054,11 +2288,147 @@ static int | |||
2054 | check_communicator_backchannel (void *cls, | 2288 | check_communicator_backchannel (void *cls, |
2055 | const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb) | 2289 | const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb) |
2056 | { | 2290 | { |
2057 | // FIXME: check encapsulated message | 2291 | const struct GNUNET_MessageHeader *inbox; |
2058 | // FIXME: check 0-termination of communcator at target | 2292 | const char *is; |
2293 | uint16_t msize; | ||
2294 | uint16_t isize; | ||
2295 | |||
2296 | msize = ntohs (cb->header.size) - sizeof (*cb); | ||
2297 | if (UINT16_MAX - msize > | ||
2298 | sizeof (struct TransportBackchannelEncapsulationMessage) + | ||
2299 | sizeof (struct TransportBackchannelRequestPayload) ) | ||
2300 | { | ||
2301 | GNUNET_break (0); | ||
2302 | return GNUNET_SYSERR; | ||
2303 | } | ||
2304 | inbox = (const struct GNUNET_MessageHeader *) &cb[1]; | ||
2305 | isize = ntohs (inbox->size); | ||
2306 | if (isize >= msize) | ||
2307 | { | ||
2308 | GNUNET_break (0); | ||
2309 | return GNUNET_SYSERR; | ||
2310 | } | ||
2311 | is = (const char *) inbox; | ||
2312 | is += isize; | ||
2313 | msize -= isize; | ||
2314 | GNUNET_assert (msize > 0); | ||
2315 | if ('\0' != is[msize-1]) | ||
2316 | { | ||
2317 | GNUNET_break (0); | ||
2318 | return GNUNET_SYSERR; | ||
2319 | } | ||
2059 | return GNUNET_OK; | 2320 | return GNUNET_OK; |
2060 | } | 2321 | } |
2061 | 2322 | ||
2323 | |||
2324 | /** | ||
2325 | * Remove memory used by expired ephemeral keys. | ||
2326 | * | ||
2327 | * @param cls NULL | ||
2328 | */ | ||
2329 | static void | ||
2330 | expire_ephemerals (void *cls) | ||
2331 | { | ||
2332 | struct EphemeralCacheEntry *ece; | ||
2333 | |||
2334 | (void) cls; | ||
2335 | ephemeral_task = NULL; | ||
2336 | while (NULL != (ece = GNUNET_CONTAINER_heap_peek (ephemeral_heap))) | ||
2337 | { | ||
2338 | if (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us) | ||
2339 | { | ||
2340 | free_ephemeral (ece); | ||
2341 | continue; | ||
2342 | } | ||
2343 | ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity, | ||
2344 | &expire_ephemerals, | ||
2345 | NULL); | ||
2346 | return; | ||
2347 | } | ||
2348 | } | ||
2349 | |||
2350 | |||
2351 | /** | ||
2352 | * Lookup ephemeral key in our #ephemeral_map. If no valid one exists, generate | ||
2353 | * one, cache it and return it. | ||
2354 | * | ||
2355 | * @param pid peer to look up ephemeral for | ||
2356 | * @param private_key[out] set to the private key | ||
2357 | * @param ephemeral_key[out] set to the key | ||
2358 | * @param ephemeral_sender_sig[out] set to the signature | ||
2359 | * @param ephemeral_validity[out] set to the validity expiration time | ||
2360 | */ | ||
2361 | static void | ||
2362 | lookup_ephemeral (const struct GNUNET_PeerIdentity *pid, | ||
2363 | struct GNUNET_CRYPTO_EcdhePrivateKey *private_key, | ||
2364 | struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key, | ||
2365 | struct GNUNET_CRYPTO_EddsaSignature *ephemeral_sender_sig, | ||
2366 | struct GNUNET_TIME_Absolute *ephemeral_validity) | ||
2367 | { | ||
2368 | struct EphemeralCacheEntry *ece; | ||
2369 | struct EphemeralConfirmation ec; | ||
2370 | |||
2371 | ece = GNUNET_CONTAINER_multipeermap_get (ephemeral_map, | ||
2372 | pid); | ||
2373 | if ( (NULL != ece) && | ||
2374 | (0 == GNUNET_TIME_absolute_get_remaining (ece->ephemeral_validity).rel_value_us) ) | ||
2375 | { | ||
2376 | free_ephemeral (ece); | ||
2377 | ece = NULL; | ||
2378 | } | ||
2379 | if (NULL == ece) | ||
2380 | { | ||
2381 | ece = GNUNET_new (struct EphemeralCacheEntry); | ||
2382 | ece->target = *pid; | ||
2383 | ece->ephemeral_validity = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_monotonic (GST_cfg), | ||
2384 | EPHEMERAL_VALIDITY); | ||
2385 | GNUNET_assert (GNUNET_OK == | ||
2386 | GNUNET_CRYPTO_ecdhe_key_create2 (&ece->private_key)); | ||
2387 | GNUNET_CRYPTO_ecdhe_key_get_public (&ece->private_key, | ||
2388 | &ece->ephemeral_key); | ||
2389 | ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL); | ||
2390 | ec.purpose.size = htonl (sizeof (ec)); | ||
2391 | ec.target = *pid; | ||
2392 | ec.ephemeral_key = ece->ephemeral_key; | ||
2393 | GNUNET_assert (GNUNET_OK == | ||
2394 | GNUNET_CRYPTO_eddsa_sign (GST_my_private_key, | ||
2395 | &ec.purpose, | ||
2396 | &ece->sender_sig)); | ||
2397 | ece->hn = GNUNET_CONTAINER_heap_insert (ephemeral_heap, | ||
2398 | ece, | ||
2399 | ece->ephemeral_validity.abs_value_us); | ||
2400 | GNUNET_assert (GNUNET_OK == | ||
2401 | GNUNET_CONTAINER_multipeermap_put (ephemeral_map, | ||
2402 | &ece->target, | ||
2403 | ece, | ||
2404 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
2405 | if (NULL == ephemeral_task) | ||
2406 | ephemeral_task = GNUNET_SCHEDULER_add_at (ece->ephemeral_validity, | ||
2407 | &expire_ephemerals, | ||
2408 | NULL); | ||
2409 | } | ||
2410 | *private_key = ece->private_key; | ||
2411 | *ephemeral_key = ece->ephemeral_key; | ||
2412 | *ephemeral_sender_sig = ece->sender_sig; | ||
2413 | *ephemeral_validity = ece->ephemeral_validity; | ||
2414 | } | ||
2415 | |||
2416 | |||
2417 | /** | ||
2418 | * We need to transmit @a hdr to @a target. If necessary, this may | ||
2419 | * involve DV routing or even broadcasting and fragmentation. | ||
2420 | * | ||
2421 | * @param target peer to receive @a hdr | ||
2422 | * @param hdr header of the message to route | ||
2423 | */ | ||
2424 | static void | ||
2425 | route_message (const struct GNUNET_PeerIdentity *target, | ||
2426 | struct GNUNET_MessageHeader *hdr) | ||
2427 | { | ||
2428 | // FIXME: send hdr to target, free hdr (possibly using DV, possibly broadcasting) | ||
2429 | GNUNET_free (hdr); | ||
2430 | } | ||
2431 | |||
2062 | 2432 | ||
2063 | /** | 2433 | /** |
2064 | * Communicator requests backchannel transmission. Process the request. | 2434 | * Communicator requests backchannel transmission. Process the request. |
@@ -2071,11 +2441,48 @@ handle_communicator_backchannel (void *cls, | |||
2071 | const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb) | 2441 | const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb) |
2072 | { | 2442 | { |
2073 | struct TransportClient *tc = cls; | 2443 | struct TransportClient *tc = cls; |
2074 | 2444 | struct GNUNET_CRYPTO_EcdhePrivateKey private_key; | |
2075 | // FIXME: determine path (possibly DV)! to target peer | 2445 | struct GNUNET_TIME_Absolute ephemeral_validity; |
2076 | // FIXME: encapsulate message, encrypt message! | 2446 | struct TransportBackchannelEncapsulationMessage *enc; |
2077 | // FIXME: possibly fragment message | 2447 | struct TransportBackchannelRequestPayload ppay; |
2078 | // FIXME: possibly DV-route message! | 2448 | char *mpos; |
2449 | uint16_t msize; | ||
2450 | |||
2451 | /* encapsulate and encrypt message */ | ||
2452 | msize = ntohs (cb->header.size) - sizeof (*cb) + sizeof (struct TransportBackchannelRequestPayload); | ||
2453 | enc = GNUNET_malloc (sizeof (*enc) + msize); | ||
2454 | enc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION); | ||
2455 | enc->header.size = htons (sizeof (*enc) + msize); | ||
2456 | enc->target = cb->pid; | ||
2457 | lookup_ephemeral (&cb->pid, | ||
2458 | &private_key, | ||
2459 | &enc->ephemeral_key, | ||
2460 | &ppay.sender_sig, | ||
2461 | &ephemeral_validity); | ||
2462 | // FIXME: setup 'iv' | ||
2463 | #if FIXME | ||
2464 | dh_key_derive (&private_key, | ||
2465 | &cb->pid, | ||
2466 | &enc->iv, | ||
2467 | &key); | ||
2468 | #endif | ||
2469 | ppay.ephemeral_validity = GNUNET_TIME_absolute_hton (ephemeral_validity); | ||
2470 | ppay.monotonic_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg)); | ||
2471 | mpos = (char *) &enc[1]; | ||
2472 | #if FIXME | ||
2473 | encrypt (key, | ||
2474 | &ppay, | ||
2475 | &mpos, | ||
2476 | sizeof (ppay)); | ||
2477 | encrypt (key, | ||
2478 | &cb[1], | ||
2479 | &mpos, | ||
2480 | ntohs (cb->header.size) - sizeof (*cb)); | ||
2481 | hmac (key, | ||
2482 | &enc->hmac); | ||
2483 | #endif | ||
2484 | route_message (&cb->pid, | ||
2485 | &enc->header); | ||
2079 | GNUNET_SERVICE_client_continue (tc->client); | 2486 | GNUNET_SERVICE_client_continue (tc->client); |
2080 | } | 2487 | } |
2081 | 2488 | ||
@@ -2260,10 +2667,28 @@ struct CommunicatorMessageContext | |||
2260 | * Additional information for flow control and about the sender. | 2667 | * Additional information for flow control and about the sender. |
2261 | */ | 2668 | */ |
2262 | struct GNUNET_TRANSPORT_IncomingMessage im; | 2669 | struct GNUNET_TRANSPORT_IncomingMessage im; |
2670 | |||
2671 | /** | ||
2672 | * Number of hops the message has travelled (if DV-routed). | ||
2673 | * FIXME: make use of this in ACK handling! | ||
2674 | */ | ||
2675 | uint16_t total_hops; | ||
2263 | }; | 2676 | }; |
2264 | 2677 | ||
2265 | 2678 | ||
2266 | /** | 2679 | /** |
2680 | * Given an inbound message @a msg from a communicator @a cmc, | ||
2681 | * demultiplex it based on the type calling the right handler. | ||
2682 | * | ||
2683 | * @param cmc context for demultiplexing | ||
2684 | * @param msg message to demultiplex | ||
2685 | */ | ||
2686 | static void | ||
2687 | demultiplex_with_cmc (struct CommunicatorMessageContext *cmc, | ||
2688 | const struct GNUNET_MessageHeader *msg); | ||
2689 | |||
2690 | |||
2691 | /** | ||
2267 | * Send ACK to communicator (if requested) and free @a cmc. | 2692 | * Send ACK to communicator (if requested) and free @a cmc. |
2268 | * | 2693 | * |
2269 | * @param cmc context for which we are done handling the message | 2694 | * @param cmc context for which we are done handling the message |
@@ -2385,9 +2810,89 @@ handle_fragment_box (void *cls, | |||
2385 | const struct TransportFragmentBox *fb) | 2810 | const struct TransportFragmentBox *fb) |
2386 | { | 2811 | { |
2387 | struct CommunicatorMessageContext *cmc = cls; | 2812 | struct CommunicatorMessageContext *cmc = cls; |
2813 | struct Neighbour *n; | ||
2814 | struct ReassemblyContext *rc; | ||
2815 | const struct GNUNET_MessageHeader *msg; | ||
2816 | uint16_t msize; | ||
2817 | |||
2818 | n = GNUNET_CONTAINER_multipeermap_get (neighbours, | ||
2819 | &cmc->im.sender); | ||
2820 | if (NULL == n) | ||
2821 | { | ||
2822 | struct GNUNET_SERVICE_Client *client = cmc->tc->client; | ||
2823 | |||
2824 | GNUNET_break (0); | ||
2825 | finish_cmc_handling (cmc); | ||
2826 | GNUNET_SERVICE_client_drop (client); | ||
2827 | return; | ||
2828 | } | ||
2829 | if (NULL == n->reassembly_map) | ||
2830 | { | ||
2831 | n->reassembly_map = GNUNET_CONTAINER_multishortmap_create (8, | ||
2832 | GNUNET_YES); | ||
2833 | n->reassembly_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
2834 | n->reassembly_timeout_task = GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION, | ||
2835 | &reassembly_cleanup_task, | ||
2836 | n); | ||
2837 | } | ||
2838 | msize = ntohs (fb->msg_size); | ||
2839 | rc = GNUNET_CONTAINER_multishortmap_get (n->reassembly_map, | ||
2840 | &fb->msg_uuid); | ||
2841 | if (NULL == rc) | ||
2842 | { | ||
2843 | rc = GNUNET_malloc (sizeof (*rc) + | ||
2844 | msize + /* reassembly payload buffer */ | ||
2845 | (msize + 7) / 8 * sizeof (uint8_t) /* bitfield */); | ||
2846 | rc->msg_uuid = fb->msg_uuid; | ||
2847 | rc->neighbour = n; | ||
2848 | rc->msg_size = msize; | ||
2849 | rc->reassembly_timeout = GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION); | ||
2850 | rc->last_frag = GNUNET_TIME_absolute_get (); | ||
2851 | rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap, | ||
2852 | rc, | ||
2853 | rc->reassembly_timeout.abs_value_us); | ||
2854 | GNUNET_assert (GNUNET_OK == | ||
2855 | GNUNET_CONTAINER_multishortmap_put (n->reassembly_map, | ||
2856 | &rc->msg_uuid, | ||
2857 | rc, | ||
2858 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
2859 | rc->bitfield = (uint8_t *) (((char *) &rc[1]) + rc->msg_size); | ||
2860 | rc->msg_missing = rc->msg_size; | ||
2861 | } | ||
2862 | if (msize != rc->msg_size) | ||
2863 | { | ||
2864 | GNUNET_break (0); | ||
2865 | finish_cmc_handling (cmc); | ||
2866 | return; | ||
2867 | } | ||
2388 | 2868 | ||
2389 | // FIXME: do work! | 2869 | // FIXME: do work: reassemble |
2390 | finish_cmc_handling (cmc); | 2870 | |
2871 | /* is reassembly complete? */ | ||
2872 | if (0 != rc->msg_missing) | ||
2873 | { | ||
2874 | /* FIXME: possibly send ACK! */ | ||
2875 | finish_cmc_handling (cmc); | ||
2876 | return; | ||
2877 | } | ||
2878 | /* reassembly is complete, verify result */ | ||
2879 | msg = (const struct GNUNET_MessageHeader *) &rc[1]; | ||
2880 | if (ntohs (msg->size) != rc->msg_size) | ||
2881 | { | ||
2882 | GNUNET_break (0); | ||
2883 | free_reassembly_context (rc); | ||
2884 | finish_cmc_handling (cmc); | ||
2885 | return; | ||
2886 | } | ||
2887 | /* successful reassembly */ | ||
2888 | /* FIXME: definitively send ACK! */ | ||
2889 | demultiplex_with_cmc (cmc, | ||
2890 | msg); | ||
2891 | /* FIXME: really free here? Might be bad if fragments are still | ||
2892 | en-route and we forget that we finished this reassembly immediately! | ||
2893 | -> keep around until timeout? | ||
2894 | -> shorten timeout based on ACK? */ | ||
2895 | free_reassembly_context (rc); | ||
2391 | } | 2896 | } |
2392 | 2897 | ||
2393 | 2898 | ||
@@ -2436,11 +2941,27 @@ handle_reliability_box (void *cls, | |||
2436 | { | 2941 | { |
2437 | struct CommunicatorMessageContext *cmc = cls; | 2942 | struct CommunicatorMessageContext *cmc = cls; |
2438 | const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1]; | 2943 | const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &rb[1]; |
2439 | 2944 | ||
2440 | // FIXME: send back reliability ACK (possibly conditional) | 2945 | if (0 == ntohl (rb->ack_countdown)) |
2441 | /* forward encapsulated message to CORE */ | 2946 | { |
2442 | handle_raw_message (cmc, | 2947 | struct TransportReliabilityAckMessage *ack; |
2443 | inbox); | 2948 | |
2949 | /* FIXME: implement cummulative ACKs and ack_countdown, | ||
2950 | then setting the avg_ack_delay field below: */ | ||
2951 | ack = GNUNET_malloc (sizeof (*ack) + | ||
2952 | sizeof (struct GNUNET_ShortHashCode)); | ||
2953 | ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK); | ||
2954 | ack->header.size = htons (sizeof (*ack) + | ||
2955 | sizeof (struct GNUNET_ShortHashCode)); | ||
2956 | memcpy (&ack[1], | ||
2957 | &rb->msg_uuid, | ||
2958 | sizeof (struct GNUNET_ShortHashCode)); | ||
2959 | route_message (&cmc->im.sender, | ||
2960 | &ack->header); | ||
2961 | } | ||
2962 | /* continue with inner message */ | ||
2963 | demultiplex_with_cmc (cmc, | ||
2964 | inbox); | ||
2444 | } | 2965 | } |
2445 | 2966 | ||
2446 | 2967 | ||
@@ -2496,7 +3017,16 @@ handle_backchannel_encapsulation (void *cls, | |||
2496 | { | 3017 | { |
2497 | struct CommunicatorMessageContext *cmc = cls; | 3018 | struct CommunicatorMessageContext *cmc = cls; |
2498 | 3019 | ||
2499 | // FIMXE: test if it is for me, if not, try to forward to target (DV routes!) | 3020 | if (0 != memcmp (&be->target, |
3021 | &GST_my_identity, | ||
3022 | sizeof (struct GNUNET_PeerIdentity))) | ||
3023 | { | ||
3024 | /* not for me, try to route to target */ | ||
3025 | route_message (&be->target, | ||
3026 | GNUNET_copy_message (&be->header)); | ||
3027 | finish_cmc_handling (cmc); | ||
3028 | return; | ||
3029 | } | ||
2500 | // FIXME: compute shared secret | 3030 | // FIXME: compute shared secret |
2501 | // FIXME: check HMAC | 3031 | // FIXME: check HMAC |
2502 | // FIXME: decrypt payload | 3032 | // FIXME: decrypt payload |
@@ -2616,10 +3146,25 @@ handle_dv_box (void *cls, | |||
2616 | const struct TransportDVBox *dvb) | 3146 | const struct TransportDVBox *dvb) |
2617 | { | 3147 | { |
2618 | struct CommunicatorMessageContext *cmc = cls; | 3148 | struct CommunicatorMessageContext *cmc = cls; |
2619 | 3149 | uint16_t size = ntohs (dvb->header.size); | |
2620 | // FIXME: are we the target? Then unbox and handle message. | 3150 | uint16_t num_hops = ntohs (dvb->num_hops); |
2621 | // FIXME: if we are not the target, shorten path and forward along. | 3151 | const struct GNUNET_PeerIdentity *hops = (const struct GNUNET_PeerIdentity *) &dvb[1]; |
2622 | finish_cmc_handling (cmc); | 3152 | const struct GNUNET_MessageHeader *inbox = (const struct GNUNET_MessageHeader *) &hops[num_hops]; |
3153 | |||
3154 | if (num_hops > 0) | ||
3155 | { | ||
3156 | // FIXME: if we are not the target, shorten path and forward along. | ||
3157 | // Try from the _end_ of hops array if we know the given | ||
3158 | // neighbour (shortening the path!). | ||
3159 | // NOTE: increment total_hops! | ||
3160 | finish_cmc_handling (cmc); | ||
3161 | return; | ||
3162 | } | ||
3163 | /* We are the target. Unbox and handle message. */ | ||
3164 | cmc->im.sender = dvb->origin; | ||
3165 | cmc->total_hops = ntohs (dvb->total_hops); | ||
3166 | demultiplex_with_cmc (cmc, | ||
3167 | inbox); | ||
2623 | } | 3168 | } |
2624 | 3169 | ||
2625 | 3170 | ||
@@ -2657,6 +3202,25 @@ handle_incoming_msg (void *cls, | |||
2657 | { | 3202 | { |
2658 | struct TransportClient *tc = cls; | 3203 | struct TransportClient *tc = cls; |
2659 | struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext); | 3204 | struct CommunicatorMessageContext *cmc = GNUNET_new (struct CommunicatorMessageContext); |
3205 | |||
3206 | cmc->tc = tc; | ||
3207 | cmc->im = *im; | ||
3208 | demultiplex_with_cmc (cmc, | ||
3209 | (const struct GNUNET_MessageHeader *) &im[1]); | ||
3210 | } | ||
3211 | |||
3212 | |||
3213 | /** | ||
3214 | * Given an inbound message @a msg from a communicator @a cmc, | ||
3215 | * demultiplex it based on the type calling the right handler. | ||
3216 | * | ||
3217 | * @param cmc context for demultiplexing | ||
3218 | * @param msg message to demultiplex | ||
3219 | */ | ||
3220 | static void | ||
3221 | demultiplex_with_cmc (struct CommunicatorMessageContext *cmc, | ||
3222 | const struct GNUNET_MessageHeader *msg) | ||
3223 | { | ||
2660 | struct GNUNET_MQ_MessageHandler handlers[] = { | 3224 | struct GNUNET_MQ_MessageHandler handlers[] = { |
2661 | GNUNET_MQ_hd_var_size (fragment_box, | 3225 | GNUNET_MQ_hd_var_size (fragment_box, |
2662 | GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT, | 3226 | GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT, |
@@ -2690,14 +3254,12 @@ handle_incoming_msg (void *cls, | |||
2690 | }; | 3254 | }; |
2691 | int ret; | 3255 | int ret; |
2692 | 3256 | ||
2693 | cmc->tc = tc; | ||
2694 | cmc->im = *im; | ||
2695 | ret = GNUNET_MQ_handle_message (handlers, | 3257 | ret = GNUNET_MQ_handle_message (handlers, |
2696 | (const struct GNUNET_MessageHeader *) &im[1]); | 3258 | msg); |
2697 | if (GNUNET_SYSERR == ret) | 3259 | if (GNUNET_SYSERR == ret) |
2698 | { | 3260 | { |
2699 | GNUNET_break (0); | 3261 | GNUNET_break (0); |
2700 | GNUNET_SERVICE_client_drop (tc->client); | 3262 | GNUNET_SERVICE_client_drop (cmc->tc->client); |
2701 | GNUNET_free (cmc); | 3263 | GNUNET_free (cmc); |
2702 | return; | 3264 | return; |
2703 | } | 3265 | } |
@@ -2705,7 +3267,7 @@ handle_incoming_msg (void *cls, | |||
2705 | { | 3267 | { |
2706 | /* unencapsulated 'raw' message */ | 3268 | /* unencapsulated 'raw' message */ |
2707 | handle_raw_message (&cmc, | 3269 | handle_raw_message (&cmc, |
2708 | (const struct GNUNET_MessageHeader *) &im[1]); | 3270 | msg); |
2709 | } | 3271 | } |
2710 | } | 3272 | } |
2711 | 3273 | ||
@@ -3731,6 +4293,11 @@ do_shutdown (void *cls) | |||
3731 | { | 4293 | { |
3732 | (void) cls; | 4294 | (void) cls; |
3733 | 4295 | ||
4296 | if (NULL != ephemeral_task) | ||
4297 | { | ||
4298 | GNUNET_SCHEDULER_cancel (ephemeral_task); | ||
4299 | ephemeral_task = NULL; | ||
4300 | } | ||
3734 | GNUNET_CONTAINER_multipeermap_iterate (neighbours, | 4301 | GNUNET_CONTAINER_multipeermap_iterate (neighbours, |
3735 | &free_neighbour_cb, | 4302 | &free_neighbour_cb, |
3736 | NULL); | 4303 | NULL); |