diff options
| author | eunhhu <[email protected]> | 2026-09-29 16:41:24 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-29 16:41:24 +0100 |
| commit | 3bd9b6c924c801dc5033510391ac251a7309219f (patch) | |
| tree | d0465bb16850b822e4b2a09a73cf370993fd4f16 | |
| parent | 590cbb9d0c73c9e48ac4a637c2e88a7e99c7965f (diff) | |
| download | pure-3bd9b6c924c801dc5033510391ac251a7309219f.tar.gz pure-3bd9b6c924c801dc5033510391ac251a7309219f.zip | |
Take no send larger than a receiver holds: 16 MiB, not 64
A sender took sends up to 64 MiB, but a receiver holds 16 MiB of a
stream not yet stored, so a send between the two went again forever.
The most a send may be is now PURE_LINK_RECORD_MOST, what a receiver
holds; test-link sends one that large whole and is refused one byte more.
| -rw-r--r-- | link/link-protocol.c | 5 | ||||
| -rw-r--r-- | link/link-protocol.h | 10 | ||||
| -rw-r--r-- | link/test-link.c | 59 |
3 files changed, 69 insertions, 5 deletions
diff --git a/link/link-protocol.c b/link/link-protocol.c index 7bc4b00..62def6f 100644 --- a/link/link-protocol.c +++ b/link/link-protocol.c @@ -51,9 +51,10 @@ static const double CUBIC_C = 0.4, CUBIC_BETA = 0.7, RENO_PACE = 3 * (1 - 0.7) / #define MS UINT64_C(1000000) /* RFC 9002's values, but a first RTT of 100 ms (a LAN's, not the 333 ms of * the Internet at large); a probe at least every second while a receiver is - * away; a record received but not stored after a second is sent again. */ + * away; a record received but not stored after a second is sent again. A + * receiver holds as much of a stream not yet stored as a record may be. */ static const uint64_t FIRST_RTT = 100 * MS, ACK_DELAY_MOST = 25 * MS, GRANULARITY = 1 * MS, PTO_MOST = 1000 * MS, - STORED_WAIT = 1000 * MS, RECORD_MOST = UINT64_C(64) << 20, HELD_MOST = UINT64_C(16) << 20, + STORED_WAIT = 1000 * MS, RECORD_MOST = PURE_LINK_RECORD_MOST, HELD_MOST = RECORD_MOST, REACH_AGAIN = 1000 * MS, REACH_RARELY = 600000 * MS; /* An epoch lasts an hour or a GiB sent; a sender that hears nothing for 2 s * with packets out, and four probes, takes its epoch for lost. */ diff --git a/link/link-protocol.h b/link/link-protocol.h index 25ff12f..b9a3eeb 100644 --- a/link/link-protocol.h +++ b/link/link-protocol.h @@ -118,8 +118,11 @@ * goes back to the first size when the larger stop coming, ยง4.3); a * source's or an input's name is 1 to PURE_LINK_NAME bytes; a receiver * keeps a packet's path (where it came from, and the address of its own it - * came to: link/link.c answers from there) in PURE_LINK_ADDRESS bytes. */ -enum { PURE_LINK_DATAGRAM = 1200, PURE_LINK_DATAGRAM_MOST = 1452, PURE_LINK_NAME = 64, PURE_LINK_ADDRESS = 48 }; + * came to: link/link.c answers from there) in PURE_LINK_ADDRESS bytes; a + * send is PURE_LINK_RECORD_MOST bytes at most (what a receiver holds of a + * stream not yet stored). */ +enum { PURE_LINK_DATAGRAM = 1200, PURE_LINK_DATAGRAM_MOST = 1452, PURE_LINK_NAME = 64, PURE_LINK_ADDRESS = 48, + PURE_LINK_RECORD_MOST = 16 << 20 }; /* Counts for a host's report: packets and records sent, records sent again, * packets lost and acknowledged, packets received, deliveries handed over, @@ -150,7 +153,8 @@ bool pure_link_sender_peer(PureLinkSender *, const unsigned char peer[PURE_SEAL_ * a key kept in hardware, say, or a test's many keys): no X25519 here. */ bool pure_link_sender_shared(PureLinkSender *, const unsigned char peer[PURE_SEAL_KEY], const unsigned char secret[32]); /* A saved send, numbered one past the last queued (any number when none - * waits); false when it cannot be kept. */ + * waits); false when it cannot be kept (or is larger than + * PURE_LINK_RECORD_MOST). */ bool pure_link_sender_queue(PureLinkSender *, uint64_t seq, const unsigned char *bytes, size_t size); /* A packet that came (the receiver's answers; others are let be). */ void pure_link_sender_take(PureLinkSender *, const unsigned char *packet, size_t size, uint64_t now); diff --git a/link/test-link.c b/link/test-link.c index 1d84804..9b709ce 100644 --- a/link/test-link.c +++ b/link/test-link.c @@ -652,6 +652,64 @@ static void flood(const char *dir) { free(w.packets); } +/* The largest send (PURE_LINK_RECORD_MOST) goes whole, over a receiver that + * never heard of the stream before; one byte more is not taken to send. */ +typedef struct { World *w; PureLinkSender *s; } Largest; +static bool deliver_largest(void *context, const PureLinkDelivery *d) { + World *w = context; + uint32_t size = (uint32_t)d->records[0] | (uint32_t)d->records[1] << 8 | (uint32_t)d->records[2] << 16 | + (uint32_t)d->records[3] << 24; + bool same = d->first == 1 && d->count == 1 && size == PURE_LINK_RECORD_MOST; + for (size_t i = 0; same && i < size; i += 4099) same = d->records[4 + i] == record_byte(1, i); + CHECK(same, "largest: a delivery of %u records from %llu, the first %u bytes", d->count, + (unsigned long long)d->first, size); + w->heard = same ? 1 : w->heard; + w->done[w->done_count++] = (PureLinkDone){d->token, 1, true, false}; + return true; +} +static bool answer_largest(void *context, const unsigned char *packet, size_t size, const unsigned char *to, + size_t to_size) { + (void)to, (void)to_size; + Largest *l = context; + pure_link_sender_take(l->s, packet, size, l->w->now); + return true; +} +static void largest(const char *dir) { + unsigned char public_a[PURE_SEAL_KEY], public_b[PURE_SEAL_KEY], out[PURE_LINK_DATAGRAM_MOST]; + char error[256]; + PureSealKey *a = key(dir, "a.key", public_a), *b = key(dir, "b.key", public_b); + World w = {0}; + PureLinkReceiver *r = pure_link_receiver(b, public_b, &(PureLinkHost){input_of, deliver_largest, &w}, error, + sizeof(error)); + PureLinkSender *s = pure_link_sender("test.ordered", "order", 0x5eed, a, public_a); + unsigned char *bytes = malloc(PURE_LINK_RECORD_MOST + 1); + if (!r || !s || !bytes || !pure_link_allow(r, "test.ordered", public_a, error, sizeof(error)) || + !pure_link_sender_peer(s, public_b)) + exit(1); + for (size_t i = 0; i <= PURE_LINK_RECORD_MOST; ++i) bytes[i] = record_byte(1, i); + CHECK(!pure_link_sender_queue(s, 1, bytes, PURE_LINK_RECORD_MOST + 1), "largest: a send past the most was taken"); + CHECK(pure_link_sender_queue(s, 1, bytes, PURE_LINK_RECORD_MOST), "largest: the most a send may be was not taken"); + free(bytes); + Largest l = {&w, s}; + uint64_t number; + for (; w.now < 60000 * MS && pure_link_sender_stored(s) < 1; w.now += MS) { + for (size_t size; (size = pure_link_sender_packet(s, out, false, w.now, &number));) + pure_link_receiver_take(r, out, size, "sender0", 7, w.now); + size_t told = w.done_count; + memcpy(w.told, w.done, told * sizeof(*w.done)); + w.done_count = 0; + pure_link_receiver_turn(r, w.told, told, w.now, answer_largest, &l); + pure_link_sender_tick(s, w.now); + } + CHECK(w.heard == 1 && pure_link_sender_stored(s) == 1, "largest: heard %llu, stored %llu after %llu ms", + (unsigned long long)w.heard, (unsigned long long)pure_link_sender_stored(s), (unsigned long long)(w.now / MS)); + printf("{\"case\":\"largest\",\"bytes\":%d,\"virtual_ms\":%llu}\n", PURE_LINK_RECORD_MOST, + (unsigned long long)(w.now / MS)); + pure_link_sender_free(s); + pure_link_receiver_free(r); + pure_seal_key_free(a), pure_seal_key_free(b); +} + int main(void) { char dir[] = "/tmp/pure-test-link-XXXXXX", error[256]; if (!mkdtemp(dir) || !pure_seal_ready(error, sizeof(error))) { @@ -710,6 +768,7 @@ int main(void) { o.hole ? "opened" : "never opened", o.datagram); impostors(dir); flood(dir); + largest(dir); char command[600]; snprintf(command, sizeof(command), "rm -rf %s", dir); if (system(command)) { /* left behind in /tmp */ } |
