aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--link/link-protocol.c68
-rw-r--r--link/link-protocol.h19
-rw-r--r--link/link.c63
-rw-r--r--link/test-link.c4
-rw-r--r--research/experiments/019-idle-links/links.c4
-rw-r--r--research/experiments/020-lossy-paths/sim.c4
6 files changed, 118 insertions, 44 deletions
diff --git a/link/link-protocol.c b/link/link-protocol.c
index fbbdcef..226d238 100644
--- a/link/link-protocol.c
+++ b/link/link-protocol.c
@@ -14,6 +14,7 @@
#include <unistd.h>
enum { VERSION = 0x70, HEADER = 21, DATAGRAM = PURE_LINK_DATAGRAM, BODY = DATAGRAM - HEADER - PURE_AEAD_TAG };
+enum { DATAGRAM_MOST = PURE_LINK_DATAGRAM_MOST, BODY_MOST = DATAGRAM_MOST - HEADER - PURE_AEAD_TAG };
/* A record that does not fit what is left of a packet goes in part, when
* at least this much of it fits. */
enum { PART_LEAST = 64 };
@@ -24,6 +25,9 @@ enum { WINDOW_FIRST = 10 * DATAGRAM, WINDOW_LEAST = 2 * DATAGRAM };
/* Reordering awaited (see PureLinkSender): at first and at most; congestion
* events with no late packet before the patience halves. */
enum { REORDER_FIRST = 3, REORDER_PACKETS_MOST = 256, REORDER_QUARTERS_MOST = 8, CALM = 16 };
+/* A probe of a larger datagram lost is tried again a second on, three
+ * times, then ten minutes on. */
+enum { REACH_TRIES = 3 };
/* CUBIC's constants (RFC 9438): the cubic's scale, and the window kept at a
* congestion event. */
static const double CUBIC_C = 0.4, CUBIC_BETA = 0.7;
@@ -32,7 +36,8 @@ static const double CUBIC_C = 0.4, CUBIC_BETA = 0.7;
* 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. */
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 = UINT64_C(64) << 20, HELD_MOST = UINT64_C(16) << 20,
+ REACH_AGAIN = 1000 * MS, REACH_RARELY = 600000 * MS;
static void put16(unsigned char *p, uint32_t v) { p[0] = (unsigned char)v, p[1] = (unsigned char)(v >> 8); }
static void put32(unsigned char *p, uint32_t v) { for (int i = 0; i < 4; ++i) p[i] = (unsigned char)(v >> 8 * i); }
@@ -167,6 +172,7 @@ typedef struct {
uint64_t episode; /* lost: the congestion episode it counted in */
uint32_t bytes;
bool eliciting, done; /* acknowledged or lost */
+ bool reach; /* a probe of a larger datagram */
bool lost, by_time; /* called lost (by time, or by later ones acknowledged), and not acknowledged since */
uint16_t count;
Unit units[UNITS];
@@ -215,6 +221,12 @@ struct PureLinkSender {
/* The window went unused (nothing to send, or no credit) when the
* sender last looked: it does not grow then (RFC 9002 §7.8). */
bool unused;
+ /* The datagram's size now; a probe of the largest flies; when the next
+ * may go, and how many were lost (RFC 8899). */
+ uint32_t datagram;
+ bool reaching;
+ uint64_t reach_at;
+ unsigned reach_lost;
uint64_t received; /* parts received and not yet stored */
uint64_t unsent_from; /* no record before this number has a part unsent */
unsigned pto_count, probes;
@@ -391,6 +403,11 @@ static void settle(PureLinkSender *l, Flight *f) {
/* A packet lost: what it carried and was not received otherwise goes again. */
static void lose(PureLinkSender *l, Flight *f, uint64_t now, bool by_time) {
settle(l, f);
+ if (f->reach) { /* the path does not carry it (yet): tried again a while on, three times, then rarely */
+ l->reaching = false;
+ l->reach_at = now + (++l->reach_lost < REACH_TRIES ? REACH_AGAIN : REACH_RARELY);
+ return;
+ }
f->lost = true;
f->by_time = by_time;
f->largest_then = l->largest_acked;
@@ -407,13 +424,13 @@ static void lose(PureLinkSender *l, Flight *f, uint64_t now, bool by_time) {
l->undo_ok = true;
}
l->recovery_start = now;
- double w = (double)l->window / DATAGRAM;
+ double w = (double)l->window / l->datagram;
l->cubic_max = w < l->cubic_max ? w * (1 + CUBIC_BETA) / 2 : w; /* fast convergence: another flow came */
l->window = most((uint64_t)((double)l->window * CUBIC_BETA), WINDOW_LEAST);
l->threshold = l->window;
l->cubic_k = cbrt(l->cubic_max * (1 - CUBIC_BETA) / CUBIC_C);
l->cubic_epoch = now;
- l->cubic_reno = (double)l->window / DATAGRAM;
+ l->cubic_reno = (double)l->window / l->datagram;
if (++l->calm_events >= CALM) { /* many events, none of them late packets: less patience */
l->reorder_packets = most(REORDER_FIRST, l->reorder_packets / 2);
l->reorder_quarters /= 2;
@@ -498,7 +515,7 @@ static void grow(PureLinkSender *l, uint64_t bytes, uint64_t now) {
l->window += bytes;
return;
}
- double w = (double)l->window / DATAGRAM, acked = (double)bytes / DATAGRAM;
+ double w = (double)l->window / l->datagram, acked = (double)bytes / l->datagram;
if (!l->cubic_epoch) { /* no event yet: the cubic starts where the window is */
l->cubic_epoch = now;
l->cubic_max = l->cubic_reno = w;
@@ -511,7 +528,7 @@ static void grow(PureLinkSender *l, uint64_t bytes, uint64_t now) {
double target = CUBIC_C * d * d * d + l->cubic_max;
target = target < w ? w : target > 1.5 * w ? 1.5 * w : target;
double next = at < l->cubic_reno ? l->cubic_reno : w + (target - w) * acked / w;
- l->window = most(l->window, (uint64_t)(next * DATAGRAM));
+ l->window = most(l->window, (uint64_t)(next * l->datagram));
}
static void on_ack(PureLinkSender *l, const unsigned char *p, size_t size, uint64_t now) {
@@ -529,6 +546,7 @@ static void on_ack(PureLinkSender *l, const unsigned char *p, size_t size, uint6
if (!f || f->done) continue;
settle(l, f);
++l->counts.acknowledged;
+ if (f->reach) l->datagram = DATAGRAM_MOST, l->reaching = false; /* the path carries it */
for (uint16_t u = 0; u < f->count; ++u) carried(l, &f->units[u], f->pn, true, now);
if (f->eliciting && f->sent > l->recovery_start && !l->unused) grow(l, f->bytes, now);
if (pn == largest) top = f;
@@ -578,8 +596,8 @@ static void on_stored(PureLinkSender *l, const unsigned char *p, size_t size, ui
}
void pure_link_sender_take(PureLinkSender *l, const unsigned char *packet, size_t n, uint64_t now) {
- unsigned char plain[DATAGRAM], nonce[PURE_AEAD_NONCE];
- if (!l->out || n < HEADER + PURE_AEAD_TAG || n > DATAGRAM || packet[0] != VERSION || get32(packet + 1) != l->peer_id)
+ unsigned char plain[DATAGRAM_MOST], nonce[PURE_AEAD_NONCE];
+ if (!l->out || n < HEADER + PURE_AEAD_TAG || n > DATAGRAM_MOST || packet[0] != VERSION || get32(packet + 1) != l->peer_id)
return; /* not ours, or an error from an earlier send (nobody listening) */
uint64_t run = get64(packet + 5), pn = get64(packet + 13);
if (!l->in || l->in_run != run) {
@@ -611,7 +629,7 @@ void pure_link_sender_take(PureLinkSender *l, const unsigned char *packet, size_
/* A packet of what is not sent yet, in order, within the receiver's credit:
* its body's size, or 0 when there is none. */
static size_t fill(PureLinkSender *l, unsigned char *body, Flight *f, bool pad) {
- size_t at = 0;
+ size_t at = 0, most = l->datagram - HEADER - PURE_AEAD_TAG;
body[at++] = F_STREAM;
at += put_names(body + at, l->source, l->input);
put32(body + at, l->shape);
@@ -634,7 +652,7 @@ static size_t fill(PureLinkSender *l, unsigned char *body, Flight *f, bool pad)
if (r->seq > base + l->credit) break;
bool full = false, fresh = !r->more && r->one.state == UNSENT, joins = run && r->seq == next;
size_t whole = (joins ? 0 : RECORDS_HEAD) + varint_size(r->size) + r->size;
- if (fresh && at + whole <= BODY) {
+ if (fresh && at + whole <= most) {
if (!joins) {
body[at] = F_RECORDS;
put64(body + at + 1, r->seq);
@@ -655,7 +673,7 @@ static size_t fill(PureLinkSender *l, unsigned char *body, Flight *f, bool pad)
for (uint32_t i = 0; i < r->parts; ++i) {
Part *p = part_of(r, i);
if (p->state != UNSENT) continue;
- size_t room = at + RECORD_HEAD < BODY ? BODY - at - RECORD_HEAD : 0;
+ size_t room = at + RECORD_HEAD < most ? most - at - RECORD_HEAD : 0;
if (f->count == UNITS || (p->length > room && (room < PART_LEAST || !cut(r, i, (uint32_t)room)))) {
full = true;
break;
@@ -678,8 +696,8 @@ static size_t fill(PureLinkSender *l, unsigned char *body, Flight *f, bool pad)
before = before && !full;
if (full) { /* the packet is full: whole, so it can go in a burst */
if (pad && f->count) {
- memset(body + at, F_PADDING, BODY - at);
- at = BODY;
+ memset(body + at, F_PADDING, most - at);
+ at = most;
}
break;
}
@@ -724,13 +742,24 @@ static size_t transmit(PureLinkSender *l, Flight *f, const unsigned char *body,
return total;
}
-size_t pure_link_sender_packet(PureLinkSender *l, unsigned char out[PURE_LINK_DATAGRAM], bool whole, uint64_t now,
+size_t pure_link_sender_packet(PureLinkSender *l, unsigned char out[PURE_LINK_DATAGRAM_MOST], bool whole, uint64_t now,
uint64_t *number) {
bool probe = l->probes > 0;
- if (!probe && l->in_flight + DATAGRAM > l->window) l->unused = false;
- if (!l->out || (!probe && l->in_flight + DATAGRAM > l->window) || !flight_room(l)) return 0;
- unsigned char body[BODY];
+ if (!probe && l->in_flight + l->datagram > l->window) l->unused = false;
+ if (!l->out || (!probe && l->in_flight + l->datagram > l->window) || !flight_room(l)) return 0;
+ unsigned char body[BODY_MOST];
Flight f = {.pn = l->next_pn, .eliciting = true};
+ if (l->datagram < DATAGRAM_MOST && !l->reaching && l->sampled && now >= l->reach_at &&
+ l->in_flight + DATAGRAM_MOST <= l->window) { /* the path may carry more: a PING of the most, padded */
+ body[0] = F_PING;
+ memset(body + 1, F_PADDING, BODY_MOST - 1);
+ f.reach = true;
+ size_t total = transmit(l, &f, body, BODY_MOST, out, now);
+ if (!total) return 0;
+ l->reaching = true;
+ *number = f.pn;
+ return total;
+ }
size_t size = fill(l, body, &f, whole);
if (!size) {
l->unused = true;
@@ -812,6 +841,7 @@ PureLinkSender *pure_link_sender(const char *source, const char *input, uint32_t
l->threshold = UINT64_MAX;
l->credit = CREDIT;
l->reorder_packets = REORDER_FIRST;
+ l->datagram = DATAGRAM;
return l;
}
@@ -836,6 +866,8 @@ bool pure_link_sender_shared(PureLinkSender *l, const unsigned char peer[PURE_SE
uint64_t pure_link_sender_queued(const PureLinkSender *l) { return l->queued; }
+size_t pure_link_sender_datagram(const PureLinkSender *l) { return l->datagram; }
+
uint64_t pure_link_sender_stored(const PureLinkSender *l) { return l->stored; }
void pure_link_sender_counts(const PureLinkSender *l, PureLinkCounts *out) {
@@ -1545,7 +1577,7 @@ static bool take_from(PureLinkReceiver *s, Peer *peer, const unsigned char *pack
Run made = {.active = a, .run = run, .seen = now, .used = true};
bool keyed = r || (derive(a->secret, peer->key, s->own_public, run, 0, made.in_key, made.in_base) &&
derive(a->secret, s->own_public, peer->key, s->run, run, made.out_key, made.out_base));
- unsigned char plain[DATAGRAM], nonce[PURE_AEAD_NONCE];
+ unsigned char plain[DATAGRAM_MOST], nonce[PURE_AEAD_NONCE];
nonce_of(nonce, r ? r->in_base : made.in_base, pn);
size_t size = n - HEADER - PURE_AEAD_TAG;
const unsigned char *key = r ? r->in_key : made.in_key, *give = key;
@@ -1616,7 +1648,7 @@ static bool take_from(PureLinkReceiver *s, Peer *peer, const unsigned char *pack
void pure_link_receiver_take(PureLinkReceiver *s, const unsigned char *packet, size_t n, const void *from,
size_t from_size, uint64_t now) {
- if (n < HEADER + PURE_AEAD_TAG || n > DATAGRAM || packet[0] != VERSION || !s->index_size) return;
+ if (n < HEADER + PURE_AEAD_TAG || n > DATAGRAM_MOST || packet[0] != VERSION || !s->index_size) return;
uint32_t id = get32(packet + 1);
size_t mask = s->index_size - 1;
uint64_t run = get64(packet + 5);
diff --git a/link/link-protocol.h b/link/link-protocol.h
index e82e599..f51260b 100644
--- a/link/link-protocol.h
+++ b/link/link-protocol.h
@@ -51,10 +51,12 @@
* Losses are detected as RFC 9002 says; congestion control is its NewReno
* (RFC 9002 §7). */
-/* A packet is at most PURE_LINK_DATAGRAM bytes; a source's or an input's
- * name is 1 to PURE_LINK_NAME bytes; a receiver keeps where a packet came
- * from (the socket's address) in PURE_LINK_ADDRESS bytes. */
-enum { PURE_LINK_DATAGRAM = 1200, PURE_LINK_NAME = 64, PURE_LINK_ADDRESS = 28 };
+/* A packet is PURE_LINK_DATAGRAM bytes at most at first, and up to
+ * PURE_LINK_DATAGRAM_MOST once the path is found to carry that many (a
+ * probe of that size acknowledged: DPLPMTUD, RFC 8899); a source's or an
+ * input's name is 1 to PURE_LINK_NAME bytes; a receiver keeps where a
+ * packet came from (the socket's address) in PURE_LINK_ADDRESS bytes. */
+enum { PURE_LINK_DATAGRAM = 1200, PURE_LINK_DATAGRAM_MOST = 1452, PURE_LINK_NAME = 64, PURE_LINK_ADDRESS = 28 };
/* Counts for a host's report: packets and records sent, records sent again,
* packets lost and acknowledged, packets received, deliveries handed over,
@@ -91,10 +93,13 @@ void pure_link_sender_take(PureLinkSender *, const unsigned char *packet, size_t
void pure_link_sender_tick(PureLinkSender *, uint64_t now);
/* The next packet to send into out, and its number: its size, or 0 when
* there is none (nothing to send, or the window is full). whole: a full
- * packet is padded to PURE_LINK_DATAGRAM (so packets may go in a burst of
- * whole datagrams, as UDP GSO sends them). */
-size_t pure_link_sender_packet(PureLinkSender *, unsigned char out[PURE_LINK_DATAGRAM], bool whole, uint64_t now,
+ * packet is padded to the sender's datagram (so packets may go in a burst
+ * of whole datagrams, as UDP GSO sends them). A probe of a larger size is
+ * larger than the datagram: it goes alone. */
+size_t pure_link_sender_packet(PureLinkSender *, unsigned char out[PURE_LINK_DATAGRAM_MOST], bool whole, uint64_t now,
uint64_t *number);
+/* The size of a full packet now. */
+size_t pure_link_sender_datagram(const PureLinkSender *);
/* A packet made but not sent (the socket refused it): what it carried is
* sent again, and it counts as never sent. */
void pure_link_sender_refused(PureLinkSender *, uint64_t number);
diff --git a/link/link.c b/link/link.c
index 449ea60..3cac405 100644
--- a/link/link.c
+++ b/link/link.c
@@ -16,10 +16,11 @@
#include <time.h>
#include <unistd.h>
-enum { DATAGRAM = PURE_LINK_DATAGRAM };
+enum { DATAGRAM = PURE_LINK_DATAGRAM, DATAGRAM_MOST = PURE_LINK_DATAGRAM_MOST };
/* Packets sent at once with UDP GSO: each but the last is a whole datagram
- * (a full one padded), and 54 of them fit a UDP datagram's 65,507 bytes. */
-enum { BURST = 54 };
+ * (a full one padded), as many as fit a UDP datagram's 65,507 bytes (54 of
+ * 1,200 bytes). */
+enum { BURST = 54, BURST_BYTES = 65507 };
#ifndef UDP_SEGMENT
#define UDP_SEGMENT 103
#endif
@@ -35,7 +36,7 @@ static uint64_t now_ns(void) {
}
/* Datagrams taken from a socket at once (recvmmsg). */
-enum { TAKE = 64, SLOT = DATAGRAM + 64 };
+enum { TAKE = 64, SLOT = DATAGRAM_MOST + 64 };
typedef struct {
unsigned char bytes[TAKE][SLOT];
struct sockaddr_storage from[TAKE];
@@ -112,6 +113,7 @@ struct PureLink {
size_t burst_size;
unsigned burst_count;
uint64_t burst_pn[BURST];
+ size_t segment; /* the datagram's size the bursts are cut at */
bool gso, no_gso;
};
@@ -197,15 +199,31 @@ static void take_answers(PureLink *l, uint64_t now) {
static bool transient(void) { return errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || errno == EINTR; }
+/* The burst in one call, cut into datagrams of the segment's size by the
+ * system (UDP GSO, asked for this call alone: a packet sent by itself is
+ * never cut, however large). */
+static ssize_t send_burst(PureLink *l) {
+ _Alignas(8) unsigned char control[CMSG_SPACE(sizeof(uint16_t))] = {0};
+ struct iovec part = {l->burst, l->burst_size};
+ struct msghdr m = {.msg_iov = &part, .msg_iovlen = 1, .msg_control = control, .msg_controllen = sizeof(control)};
+ struct cmsghdr *c = CMSG_FIRSTHDR(&m);
+ c->cmsg_level = SOL_UDP;
+ c->cmsg_type = UDP_SEGMENT;
+ c->cmsg_len = CMSG_LEN(sizeof(uint16_t));
+ uint16_t segment = (uint16_t)l->segment;
+ memcpy(CMSG_DATA(c), &segment, sizeof(segment));
+ return sendmsg(l->fd, &m, 0);
+}
+
/* The packets of the burst to the socket (each but the last a whole
* datagram): with GSO in one call, else one by one. */
static void flush(PureLink *l) {
unsigned n = l->burst_count, sent = 0;
bool whole = n > 1 && l->gso;
- if (whole && send(l->fd, l->burst, l->burst_size, 0) >= 0) sent = n;
+ if (whole && send_burst(l) >= 0) sent = n;
else if (whole && !transient()) l->gso = false, whole = false; /* no GSO here: one by one from now on */
for (size_t at = 0; !whole && sent < n; ++sent) {
- size_t size = sent + 1 < n ? DATAGRAM : l->burst_size - at;
+ size_t size = sent + 1 < n ? l->segment : l->burst_size - at;
if (send(l->fd, l->burst + at, size, 0) < 0 && transient()) break;
at += size;
}
@@ -215,17 +233,28 @@ static void flush(PureLink *l) {
}
/* Packets while the sender has them (up to 128 a turn), into bursts: a
- * short packet ends one. */
+ * short packet ends one, and a probe of a larger datagram goes alone. */
static void send_packets(PureLink *l, uint64_t now) {
l->queued_new = false; /* all queued is looked at now */
+ l->segment = pure_link_sender_datagram(l->sender); /* larger once the path is found to carry it */
+ unsigned most = BURST_BYTES / l->segment < BURST ? (unsigned)(BURST_BYTES / l->segment) : BURST;
for (unsigned n = 0; n < 128; ++n) {
- if (l->burst_count && l->burst_size != (size_t)l->burst_count * DATAGRAM) flush(l); /* the last was short */
+ if (l->burst_count && l->burst_size != (size_t)l->burst_count * l->segment) flush(l); /* the last was short */
uint64_t pn;
size_t size = pure_link_sender_packet(l->sender, l->burst + l->burst_size, l->gso, now, &pn);
if (!size) break;
+ if (size > l->segment) { /* a probe: the burst before it, then it alone */
+ unsigned char probe[DATAGRAM_MOST];
+ memcpy(probe, l->burst + l->burst_size, size);
+ flush(l);
+ memcpy(l->burst, probe, size);
+ l->burst_pn[0] = pn, l->burst_count = 1, l->burst_size = size;
+ flush(l);
+ continue;
+ }
l->burst_pn[l->burst_count++] = pn;
l->burst_size += size;
- if (l->burst_count == BURST) flush(l);
+ if (l->burst_count == most) flush(l);
}
flush(l);
}
@@ -274,15 +303,23 @@ bool pure_link_start(PureLink *l, void (*notify)(void *), void *context, char *e
}
l->fd = socket(found->ai_family, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
bool ok = l->fd >= 0 && !connect(l->fd, found->ai_addr, found->ai_addrlen);
+ int buffer = 4 << 20, family = found->ai_family;
freeaddrinfo(found);
- int buffer = 4 << 20;
if (ok) {
setsockopt(l->fd, SOL_SOCKET, SO_SNDBUF, &buffer, sizeof(buffer));
setsockopt(l->fd, SOL_SOCKET, SO_RCVBUF, &buffer, sizeof(buffer));
+ /* Never cut up on the way (the don't-fragment bit): a packet the
+ * path does not carry is lost, as a probe of a larger size must be. */
+ int probe = IP_PMTUDISC_PROBE, probe6 = IPV6_PMTUDISC_PROBE;
+ if (family == AF_INET6) setsockopt(l->fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &probe6, sizeof(probe6));
+ else setsockopt(l->fd, IPPROTO_IP, IP_MTU_DISCOVER, &probe, sizeof(probe));
}
- int segment = DATAGRAM;
- l->gso = ok && !l->no_gso && !setsockopt(l->fd, SOL_UDP, UDP_SEGMENT, &segment, sizeof(segment));
- ok = ok && l->keyed && (l->burst = malloc((size_t)BURST * DATAGRAM)) && (l->taking = malloc(sizeof(*l->taking))) &&
+ /* GSO where the system has it: asked for each burst, never for the socket. */
+ int segment = DATAGRAM, none = 0;
+ l->segment = DATAGRAM;
+ l->gso = ok && !l->no_gso && !setsockopt(l->fd, SOL_UDP, UDP_SEGMENT, &segment, sizeof(segment)) &&
+ !setsockopt(l->fd, SOL_UDP, UDP_SEGMENT, &none, sizeof(none));
+ ok = ok && l->keyed && (l->burst = malloc(BURST_BYTES + DATAGRAM_MOST)) && (l->taking = malloc(sizeof(*l->taking))) &&
(l->wake = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)) >= 0;
l->notify = notify;
l->context = context;
diff --git a/link/test-link.c b/link/test-link.c
index 8be32a9..a05f8bc 100644
--- a/link/test-link.c
+++ b/link/test-link.c
@@ -45,7 +45,7 @@ typedef struct {
uint64_t at;
bool to_receiver;
size_t size;
- unsigned char bytes[PURE_LINK_DATAGRAM];
+ unsigned char bytes[PURE_LINK_DATAGRAM_MOST];
} Packet;
typedef struct {
@@ -185,7 +185,7 @@ static Outcome run(const Case *c, const char *dir) {
PureLinkReceiver *r = receiver_of(&w, b, public_b, public_a, memo, c->idle_ms);
PureLinkCounts sent_before = {0}, heard_before = {0};
bool receiver_restarted = !c->receiver_restart_after, sender_restarted = !c->sender_restart_after;
- unsigned char out[PURE_LINK_DATAGRAM];
+ unsigned char out[PURE_LINK_DATAGRAM_MOST];
while (w.heard < c->records || pure_link_sender_stored(s) < c->records) {
CHECK(w.now < 600000 * MS, "%s: not done after ten minutes (heard %llu of %llu)", c->name,
(unsigned long long)w.heard, (unsigned long long)c->records);
diff --git a/research/experiments/019-idle-links/links.c b/research/experiments/019-idle-links/links.c
index 8c52550..4c77482 100644
--- a/research/experiments/019-idle-links/links.c
+++ b/research/experiments/019-idle-links/links.c
@@ -179,7 +179,7 @@ static PureLinkSender *sender_of(size_t device) {
/* What a sender has to send, to its socket. */
static void send_packets(PureLinkSender *s, int fd, uint64_t now) {
- unsigned char packet[PURE_LINK_DATAGRAM];
+ unsigned char packet[PURE_LINK_DATAGRAM_MOST];
uint64_t number;
for (size_t size; (size = pure_link_sender_packet(s, packet, false, now, &number));) {
if (send(fd, packet, size, 0) < 0 && (errno == EAGAIN || errno == ENOBUFS)) {
@@ -192,7 +192,7 @@ static void send_packets(PureLinkSender *s, int fd, uint64_t now) {
/* Answers waiting on fd, to the sender. */
static void take_answers(PureLinkSender *s, int fd, uint64_t now) {
- unsigned char packet[PURE_LINK_DATAGRAM + 64];
+ unsigned char packet[PURE_LINK_DATAGRAM_MOST + 64];
for (ssize_t got; (got = recv(fd, packet, sizeof(packet), 0)) > 0;) pure_link_sender_take(s, packet, (size_t)got, now);
}
diff --git a/research/experiments/020-lossy-paths/sim.c b/research/experiments/020-lossy-paths/sim.c
index 00f93d6..699c9d4 100644
--- a/research/experiments/020-lossy-paths/sim.c
+++ b/research/experiments/020-lossy-paths/sim.c
@@ -19,7 +19,7 @@ typedef struct {
uint64_t at;
bool to_receiver;
size_t size;
- unsigned char bytes[PURE_LINK_DATAGRAM];
+ unsigned char bytes[PURE_LINK_DATAGRAM_MOST];
} Packet;
static uint64_t sim_seed;
@@ -111,7 +111,7 @@ int main(int argc, char **argv) {
unsigned char *bytes = calloc(1, size + 1);
for (uint64_t seq = 1; seq <= records; ++seq)
if (!pure_link_sender_queue(s, seq, bytes, size)) return 1;
- unsigned char out[PURE_LINK_DATAGRAM];
+ unsigned char out[PURE_LINK_DATAGRAM_MOST];
uint64_t sample_at = 0, window_sum = 0, rtt_sum = 0, samples = 0, window_least = UINT64_MAX;
PureLinkDone told[64];
while (heard < records || s->stored < records) {