summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alessandro Ghedini <alessandro@ghedini.me> 2021-05-24 13:04:23 +0100
committerGravatar GitHub <noreply@github.com> 2021-05-24 13:04:23 +0100
commit6d070ed8694216806f3ce689d71ceb7ad76d425e (patch)
treeda55560d974df791751c697dbc7ca8ff2cb41cab
parentcbce40c1426806fc04fef3c307823453c1f35ad2 (diff)
downloadquiche-6d070ed8694216806f3ce689d71ceb7ad76d425e.tar.gz
quiche-6d070ed8694216806f3ce689d71ceb7ad76d425e.tar.zst
quiche-6d070ed8694216806f3ce689d71ceb7ad76d425e.zip
network path awareness
Currently quiche does not hold any information about the network path of a QUIC connection (such as the address of the peer), and the application is responsible for maintaining such information. This means that in case of a network migration, the application is responsible for detecting the change and switching over to new path, however there is currently no way for an application to actually validate a new path, as required by the QUIC spec. Adding an ad-hoc API to only expose path validation to applications would likely be very cumbersome, due to the synchronization needed between an application and quiche on the state of the current path, and any other path being probed. Instead, this change makes quiche be aware of the network path being used. The application needs to communicate the destination address of a connection upon creationg (via `accept()` or `connect()`), as well as the source address of received packets (via `recv()` and the new `RecvInfo` structure). In turn quiche will provide the application with the destination address of generated packets (via `send()` and the new `SendInfo` structure). Currently only the destination address of a connection is tracked, which would allow quiche to handle responding to migrations transparently from the application (but this will be added as a separate change). Additional fields can later be added to `RecvInfo` and `SendInfo`, such as the address of the local endpoint in order to be able to initiate migrations, rather than just respond to them.
-rw-r--r--examples/client.c31
-rw-r--r--examples/client.rs17
-rw-r--r--examples/http3-client.c31
-rw-r--r--examples/http3-client.rs17
-rw-r--r--examples/http3-server.c33
-rw-r--r--examples/http3-server.rs38
-rw-r--r--examples/server.c48
-rw-r--r--examples/server.rs38
-rw-r--r--extras/nginx/nginx-1.16.patch40
-rw-r--r--fuzz/src/packet_recv_client.rs19
-rw-r--r--fuzz/src/packet_recv_server.rs11
-rw-r--r--include/quiche.h24
-rw-r--r--src/ffi.rs157
-rw-r--r--src/h3/mod.rs15
-rw-r--r--src/lib.rs440
-rw-r--r--tools/apps/src/bin/quiche-server.rs34
-rw-r--r--tools/apps/src/client.rs17
-rw-r--r--tools/apps/src/common.rs3
-rw-r--r--tools/http3_test/src/runner.rs17
19 files changed, 717 insertions, 313 deletions
diff --git a/examples/client.c b/examples/client.c
index cef13670..714e8d42 100644
--- a/examples/client.c
+++ b/examples/client.c
@@ -61,8 +61,11 @@ static void debug_log(const char *line, void *argp) {
static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
static uint8_t out[MAX_DATAGRAM_SIZE];
+ quiche_send_info send_info;
+
while (1) {
- ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out));
+ ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out),
+ &send_info);
if (written == QUICHE_ERR_DONE) {
fprintf(stderr, "done writing\n");
@@ -74,7 +77,10 @@ static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
return;
}
- ssize_t sent = send(conn_io->sock, out, written, 0);
+ ssize_t sent = sendto(conn_io->sock, out, written, 0,
+ (struct sockaddr *) &send_info.to,
+ send_info.to_len);
+
if (sent != written) {
perror("failed to send");
return;
@@ -96,7 +102,13 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
static uint8_t buf[65535];
while (1) {
- ssize_t read = recv(conn_io->sock, buf, sizeof(buf), 0);
+ struct sockaddr_storage peer_addr;
+ socklen_t peer_addr_len = sizeof(peer_addr);
+ memset(&peer_addr, 0, peer_addr_len);
+
+ ssize_t read = recvfrom(conn_io->sock, buf, sizeof(buf), 0,
+ (struct sockaddr *) &peer_addr,
+ &peer_addr_len);
if (read < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
@@ -108,7 +120,13 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
return;
}
- ssize_t done = quiche_conn_recv(conn_io->conn, buf, read);
+ quiche_recv_info recv_info = {
+ (struct sockaddr *) &peer_addr,
+
+ peer_addr_len,
+ };
+
+ ssize_t done = quiche_conn_recv(conn_io->conn, buf, read, &recv_info);
if (done < 0) {
fprintf(stderr, "failed to process packet\n");
@@ -269,8 +287,9 @@ int main(int argc, char *argv[]) {
return -1;
}
- quiche_conn *conn = quiche_connect(host, (const uint8_t *) scid,
- sizeof(scid), config);
+ quiche_conn *conn = quiche_connect(host, (const uint8_t*) scid, sizeof(scid),
+ peer->ai_addr, peer->ai_addrlen, config);
+
if (conn == NULL) {
fprintf(stderr, "failed to create connection\n");
return -1;
diff --git a/examples/client.rs b/examples/client.rs
index 53a22445..ebce074b 100644
--- a/examples/client.rs
+++ b/examples/client.rs
@@ -109,7 +109,8 @@ fn main() {
let scid = quiche::ConnectionId::from_ref(&scid);
// Create a QUIC connection and initiate handshake.
- let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
+ let mut conn =
+ quiche::connect(url.domain(), &scid, peer_addr, &mut config).unwrap();
info!(
"connecting to {:} from {:} with scid {}",
@@ -118,9 +119,9 @@ fn main() {
hex_dump(&scid)
);
- let write = conn.send(&mut out).expect("initial send failed");
+ let (write, send_info) = conn.send(&mut out).expect("initial send failed");
- while let Err(e) = socket.send(&out[..write]) {
+ while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
continue;
@@ -151,7 +152,7 @@ fn main() {
break 'read;
}
- let len = match socket.recv(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -168,8 +169,10 @@ fn main() {
debug!("got {} bytes", len);
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match conn.recv(&mut buf[..len]) {
+ let read = match conn.recv(&mut buf[..len], recv_info) {
Ok(v) => v,
Err(e) => {
@@ -233,7 +236,7 @@ fn main() {
// Generate outgoing QUIC packets and send them on the UDP socket, until
// quiche reports that there are no more packets to be sent.
loop {
- let write = match conn.send(&mut out) {
+ let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -249,7 +252,7 @@ fn main() {
},
};
- if let Err(e) = socket.send(&out[..write]) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
diff --git a/examples/http3-client.c b/examples/http3-client.c
index 9312095a..e2334835 100644
--- a/examples/http3-client.c
+++ b/examples/http3-client.c
@@ -65,8 +65,11 @@ static void debug_log(const char *line, void *argp) {
static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
static uint8_t out[MAX_DATAGRAM_SIZE];
+ quiche_send_info send_info;
+
while (1) {
- ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out));
+ ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out),
+ &send_info);
if (written == QUICHE_ERR_DONE) {
fprintf(stderr, "done writing\n");
@@ -78,7 +81,10 @@ static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
return;
}
- ssize_t sent = send(conn_io->sock, out, written, 0);
+ ssize_t sent = sendto(conn_io->sock, out, written, 0,
+ (struct sockaddr *) &send_info.to,
+ send_info.to_len);
+
if (sent != written) {
perror("failed to send");
return;
@@ -109,7 +115,13 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
static uint8_t buf[65535];
while (1) {
- ssize_t read = recv(conn_io->sock, buf, sizeof(buf), 0);
+ struct sockaddr_storage peer_addr;
+ socklen_t peer_addr_len = sizeof(peer_addr);
+ memset(&peer_addr, 0, peer_addr_len);
+
+ ssize_t read = recvfrom(conn_io->sock, buf, sizeof(buf), 0,
+ (struct sockaddr *) &peer_addr,
+ &peer_addr_len);
if (read < 0) {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
@@ -121,7 +133,13 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
return;
}
- ssize_t done = quiche_conn_recv(conn_io->conn, buf, read);
+ quiche_recv_info recv_info = {
+ (struct sockaddr *) &peer_addr,
+
+ peer_addr_len,
+ };
+
+ ssize_t done = quiche_conn_recv(conn_io->conn, buf, read, &recv_info);
if (done < 0) {
fprintf(stderr, "failed to process packet: %zd\n", done);
@@ -371,8 +389,9 @@ int main(int argc, char *argv[]) {
return -1;
}
- quiche_conn *conn = quiche_connect(host, (const uint8_t *) scid,
- sizeof(scid), config);
+ quiche_conn *conn = quiche_connect(host, (const uint8_t*) scid, sizeof(scid),
+ peer->ai_addr, peer->ai_addrlen, config);
+
if (conn == NULL) {
fprintf(stderr, "failed to create connection\n");
return -1;
diff --git a/examples/http3-client.rs b/examples/http3-client.rs
index 1efd0523..4fd612eb 100644
--- a/examples/http3-client.rs
+++ b/examples/http3-client.rs
@@ -108,7 +108,8 @@ fn main() {
let scid = quiche::ConnectionId::from_ref(&scid);
// Create a QUIC connection and initiate handshake.
- let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
+ let mut conn =
+ quiche::connect(url.domain(), &scid, peer_addr, &mut config).unwrap();
info!(
"connecting to {:} from {:} with scid {}",
@@ -117,9 +118,9 @@ fn main() {
hex_dump(&scid)
);
- let write = conn.send(&mut out).expect("initial send failed");
+ let (write, send_info) = conn.send(&mut out).expect("initial send failed");
- while let Err(e) = socket.send(&out[..write]) {
+ while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
continue;
@@ -169,7 +170,7 @@ fn main() {
break 'read;
}
- let len = match socket.recv(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -186,8 +187,10 @@ fn main() {
debug!("got {} bytes", len);
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match conn.recv(&mut buf[..len]) {
+ let read = match conn.recv(&mut buf[..len], recv_info) {
Ok(v) => v,
Err(e) => {
@@ -283,7 +286,7 @@ fn main() {
// Generate outgoing QUIC packets and send them on the UDP socket, until
// quiche reports that there are no more packets to be sent.
loop {
- let write = match conn.send(&mut out) {
+ let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -299,7 +302,7 @@ fn main() {
},
};
- if let Err(e) = socket.send(&out[..write]) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
diff --git a/examples/http3-server.c b/examples/http3-server.c
index b315dba1..73c29aec 100644
--- a/examples/http3-server.c
+++ b/examples/http3-server.c
@@ -89,8 +89,11 @@ static void debug_log(const char *line, void *argp) {
static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
static uint8_t out[MAX_DATAGRAM_SIZE];
+ quiche_send_info send_info;
+
while (1) {
- ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out));
+ ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out),
+ &send_info);
if (written == QUICHE_ERR_DONE) {
fprintf(stderr, "done writing\n");
@@ -173,7 +176,9 @@ static uint8_t *gen_cid(uint8_t *cid, size_t cid_len) {
}
static struct conn_io *create_conn(uint8_t *scid, size_t scid_len,
- uint8_t *odcid, size_t odcid_len) {
+ uint8_t *odcid, size_t odcid_len,
+ struct sockaddr_storage *peer_addr,
+ socklen_t peer_addr_len) {
struct conn_io *conn_io = calloc(1, sizeof(*conn_io));
if (conn_io == NULL) {
fprintf(stderr, "failed to allocate connection IO\n");
@@ -187,7 +192,11 @@ static struct conn_io *create_conn(uint8_t *scid, size_t scid_len,
memcpy(conn_io->cid, scid, LOCAL_CONN_ID_LEN);
quiche_conn *conn = quiche_accept(conn_io->cid, LOCAL_CONN_ID_LEN,
- odcid, odcid_len, config);
+ odcid, odcid_len,
+ (struct sockaddr *) peer_addr,
+ peer_addr_len,
+ config);
+
if (conn == NULL) {
fprintf(stderr, "failed to create connection\n");
return NULL;
@@ -196,6 +205,9 @@ static struct conn_io *create_conn(uint8_t *scid, size_t scid_len,
conn_io->sock = conns->sock;
conn_io->conn = conn;
+ memcpy(&conn_io->peer_addr, &peer_addr, peer_addr_len);
+ conn_io->peer_addr_len = peer_addr_len;
+
ev_init(&conn_io->timer, timeout_cb);
conn_io->timer.data = conn_io;
@@ -334,16 +346,21 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
continue;
}
- conn_io = create_conn(dcid, dcid_len, odcid, odcid_len);
+ conn_io = create_conn(dcid, dcid_len, odcid, odcid_len,
+ &peer_addr, peer_addr_len);
+
if (conn_io == NULL) {
continue;
}
-
- memcpy(&conn_io->peer_addr, &peer_addr, peer_addr_len);
- conn_io->peer_addr_len = peer_addr_len;
}
- ssize_t done = quiche_conn_recv(conn_io->conn, buf, read);
+ quiche_recv_info recv_info = {
+ (struct sockaddr *) &peer_addr,
+
+ peer_addr_len,
+ };
+
+ ssize_t done = quiche_conn_recv(conn_io->conn, buf, read, &recv_info);
if (done < 0) {
fprintf(stderr, "failed to process packet: %zd\n", done);
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index abe3016a..b1fc1edc 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -53,8 +53,7 @@ struct Client {
partial_responses: HashMap<u64, PartialResponse>,
}
-type ClientMap =
- HashMap<quiche::ConnectionId<'static>, (net::SocketAddr, Client)>;
+type ClientMap = HashMap<quiche::ConnectionId<'static>, Client>;
fn main() {
let mut buf = [0; 65535];
@@ -124,8 +123,7 @@ fn main() {
// Find the shorter timeout from all the active connections.
//
// TODO: use event loop that properly supports timers
- let timeout =
- clients.values().filter_map(|(_, c)| c.conn.timeout()).min();
+ let timeout = clients.values().filter_map(|c| c.conn.timeout()).min();
poll.poll(&mut events, timeout).unwrap();
@@ -138,12 +136,12 @@ fn main() {
if events.is_empty() {
debug!("timed out");
- clients.values_mut().for_each(|(_, c)| c.conn.on_timeout());
+ clients.values_mut().for_each(|c| c.conn.on_timeout());
break 'read;
}
- let (len, src) = match socket.recv_from(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -183,7 +181,7 @@ fn main() {
// Lookup a connection based on the packet's connection ID. If there
// is no connection matching, create a new one.
- let (_, client) = if !clients.contains_key(&hdr.dcid) &&
+ let client = if !clients.contains_key(&hdr.dcid) &&
!clients.contains_key(&conn_id)
{
if hdr.ty != quiche::Type::Initial {
@@ -200,7 +198,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &src) {
+ if let Err(e) = socket.send_to(out, &from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -223,7 +221,7 @@ fn main() {
if token.is_empty() {
warn!("Doing stateless retry");
- let new_token = mint_token(&hdr, &src);
+ let new_token = mint_token(&hdr, &from);
let len = quiche::retry(
&hdr.scid,
@@ -237,7 +235,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &src) {
+ if let Err(e) = socket.send_to(out, &from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -248,7 +246,7 @@ fn main() {
continue 'read;
}
- let odcid = validate_token(&src, token);
+ let odcid = validate_token(&from, token);
// The token was not valid, meaning the retry failed, so
// drop the packet.
@@ -269,7 +267,8 @@ fn main() {
debug!("New connection: dcid={:?} scid={:?}", hdr.dcid, scid);
let conn =
- quiche::accept(&scid, odcid.as_ref(), &mut config).unwrap();
+ quiche::accept(&scid, odcid.as_ref(), from, &mut config)
+ .unwrap();
let client = Client {
conn,
@@ -277,7 +276,7 @@ fn main() {
partial_responses: HashMap::new(),
};
- clients.insert(scid.clone(), (src, client));
+ clients.insert(scid.clone(), client);
clients.get_mut(&scid).unwrap()
} else {
@@ -288,8 +287,10 @@ fn main() {
}
};
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match client.conn.recv(pkt_buf) {
+ let read = match client.conn.recv(pkt_buf, recv_info) {
Ok(v) => v,
Err(e) => {
@@ -384,9 +385,9 @@ fn main() {
// Generate outgoing QUIC packets for all active connections and send
// them on the UDP socket, until quiche reports that there are no more
// packets to be sent.
- for (peer, client) in clients.values_mut() {
+ for client in clients.values_mut() {
loop {
- let write = match client.conn.send(&mut out) {
+ let (write, send_info) = match client.conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -402,8 +403,7 @@ fn main() {
},
};
- // TODO: coalesce packets.
- if let Err(e) = socket.send_to(&out[..write], &peer) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -417,7 +417,7 @@ fn main() {
}
// Garbage collect closed connections.
- clients.retain(|_, (_, ref mut c)| {
+ clients.retain(|_, ref mut c| {
debug!("Collecting garbage");
if c.conn.is_closed() {
diff --git a/examples/server.c b/examples/server.c
index 01ebef12..a97250fe 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -86,8 +86,11 @@ static void debug_log(const char *line, void *argp) {
static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
static uint8_t out[MAX_DATAGRAM_SIZE];
+ quiche_send_info send_info;
+
while (1) {
- ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out));
+ ssize_t written = quiche_conn_send(conn_io->conn, out, sizeof(out),
+ &send_info);
if (written == QUICHE_ERR_DONE) {
fprintf(stderr, "done writing\n");
@@ -100,8 +103,9 @@ static void flush_egress(struct ev_loop *loop, struct conn_io *conn_io) {
}
ssize_t sent = sendto(conn_io->sock, out, written, 0,
- (struct sockaddr *) &conn_io->peer_addr,
- conn_io->peer_addr_len);
+ (struct sockaddr *) &send_info.to,
+ send_info.to_len);
+
if (sent != written) {
perror("failed to send");
return;
@@ -169,18 +173,28 @@ static uint8_t *gen_cid(uint8_t *cid, size_t cid_len) {
return cid;
}
-static struct conn_io *create_conn(uint8_t *dcid, size_t dcid_len, uint8_t *odcid,
- size_t odcid_len) {
- struct conn_io *conn_io = malloc(sizeof(*conn_io));
+static struct conn_io *create_conn(uint8_t *scid, size_t scid_len,
+ uint8_t *odcid, size_t odcid_len,
+ struct sockaddr_storage *peer_addr,
+ socklen_t peer_addr_len) {
+ struct conn_io *conn_io = calloc(1, sizeof(*conn_io));
if (conn_io == NULL) {
fprintf(stderr, "failed to allocate connection IO\n");
return NULL;
}
- memcpy(conn_io->cid, dcid, LOCAL_CONN_ID_LEN);
+ if (scid_len != LOCAL_CONN_ID_LEN) {
+ fprintf(stderr, "failed, scid length too short\n");
+ }
+
+ memcpy(conn_io->cid, scid, LOCAL_CONN_ID_LEN);
quiche_conn *conn = quiche_accept(conn_io->cid, LOCAL_CONN_ID_LEN,
- odcid, odcid_len, config);
+ odcid, odcid_len,
+ (struct sockaddr *) peer_addr,
+ peer_addr_len,
+ config);
+
if (conn == NULL) {
fprintf(stderr, "failed to create connection\n");
return NULL;
@@ -189,6 +203,9 @@ static struct conn_io *create_conn(uint8_t *dcid, size_t dcid_len, uint8_t *odci
conn_io->sock = conns->sock;
conn_io->conn = conn;
+ memcpy(&conn_io->peer_addr, &peer_addr, peer_addr_len);
+ conn_io->peer_addr_len = peer_addr_len;
+
ev_init(&conn_io->timer, timeout_cb);
conn_io->timer.data = conn_io;
@@ -318,16 +335,21 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
continue;
}
- conn_io = create_conn(dcid, dcid_len, odcid, odcid_len);
+ conn_io = create_conn(dcid, dcid_len, odcid, odcid_len,
+ &peer_addr, peer_addr_len);
+
if (conn_io == NULL) {
continue;
}
-
- memcpy(&conn_io->peer_addr, &peer_addr, peer_addr_len);
- conn_io->peer_addr_len = peer_addr_len;
}
- ssize_t done = quiche_conn_recv(conn_io->conn, buf, read);
+ quiche_recv_info recv_info = {
+ (struct sockaddr *) &peer_addr,
+
+ peer_addr_len,
+ };
+
+ ssize_t done = quiche_conn_recv(conn_io->conn, buf, read, &recv_info);
if (done < 0) {
fprintf(stderr, "failed to process packet: %zd\n", done);
diff --git a/examples/server.rs b/examples/server.rs
index 4e6e8b39..90f01022 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -47,8 +47,7 @@ struct Client {
partial_responses: HashMap<u64, PartialResponse>,
}
-type ClientMap =
- HashMap<quiche::ConnectionId<'static>, (net::SocketAddr, Client)>;
+type ClientMap = HashMap<quiche::ConnectionId<'static>, Client>;
fn main() {
let mut buf = [0; 65535];
@@ -118,8 +117,7 @@ fn main() {
// Find the shorter timeout from all the active connections.
//
// TODO: use event loop that properly supports timers
- let timeout =
- clients.values().filter_map(|(_, c)| c.conn.timeout()).min();
+ let timeout = clients.values().filter_map(|c| c.conn.timeout()).min();
poll.poll(&mut events, timeout).unwrap();
@@ -132,12 +130,12 @@ fn main() {
if events.is_empty() {
debug!("timed out");
- clients.values_mut().for_each(|(_, c)| c.conn.on_timeout());
+ clients.values_mut().for_each(|c| c.conn.on_timeout());
break 'read;
}
- let (len, src) = match socket.recv_from(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -177,7 +175,7 @@ fn main() {
// Lookup a connection based on the packet's connection ID. If there
// is no connection matching, create a new one.
- let (_, client) = if !clients.contains_key(&hdr.dcid) &&
+ let client = if !clients.contains_key(&hdr.dcid) &&
!clients.contains_key(&conn_id)
{
if hdr.ty != quiche::Type::Initial {
@@ -194,7 +192,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &src) {
+ if let Err(e) = socket.send_to(out, &from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -217,7 +215,7 @@ fn main() {
if token.is_empty() {
warn!("Doing stateless retry");
- let new_token = mint_token(&hdr, &src);
+ let new_token = mint_token(&hdr, &from);
let len = quiche::retry(
&hdr.scid,
@@ -231,7 +229,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &src) {
+ if let Err(e) = socket.send_to(out, &from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -242,7 +240,7 @@ fn main() {
continue 'read;
}
- let odcid = validate_token(&src, token);
+ let odcid = validate_token(&from, token);
// The token was not valid, meaning the retry failed, so
// drop the packet.
@@ -263,14 +261,15 @@ fn main() {
debug!("New connection: dcid={:?} scid={:?}", hdr.dcid, scid);
let conn =
- quiche::accept(&scid, odcid.as_ref(), &mut config).unwrap();
+ quiche::accept(&scid, odcid.as_ref(), from, &mut config)
+ .unwrap();
let client = Client {
conn,
partial_responses: HashMap::new(),
};
- clients.insert(scid.clone(), (src, client));
+ clients.insert(scid.clone(), client);
clients.get_mut(&scid).unwrap()
} else {
@@ -281,8 +280,10 @@ fn main() {
}
};
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match client.conn.recv(pkt_buf) {
+ let read = match client.conn.recv(pkt_buf, recv_info) {
Ok(v) => v,
Err(e) => {
@@ -329,9 +330,9 @@ fn main() {
// Generate outgoing QUIC packets for all active connections and send
// them on the UDP socket, until quiche reports that there are no more
// packets to be sent.
- for (peer, client) in clients.values_mut() {
+ for client in clients.values_mut() {
loop {
- let write = match client.conn.send(&mut out) {
+ let (write, send_info) = match client.conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -347,8 +348,7 @@ fn main() {
},
};
- // TODO: coalesce packets.
- if let Err(e) = socket.send_to(&out[..write], &peer) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;
@@ -362,7 +362,7 @@ fn main() {
}
// Garbage collect closed connections.
- clients.retain(|_, (_, ref mut c)| {
+ clients.retain(|_, ref mut c| {
debug!("Collecting garbage");
if c.conn.is_closed() {
diff --git a/extras/nginx/nginx-1.16.patch b/extras/nginx/nginx-1.16.patch
index ccb251c6..f8cb7c4b 100644
--- a/extras/nginx/nginx-1.16.patch
+++ b/extras/nginx/nginx-1.16.patch
@@ -1,4 +1,4 @@
-From 8159b9f5ea2f6f0fbb31f78b629009d615c428d3 Mon Sep 17 00:00:00 2001
+From 3f07343d97a8efacc90880d9d42d79c522e4ba34 Mon Sep 17 00:00:00 2001
From: Alessandro Ghedini <alessandro@cloudflare.com>
Date: Thu, 22 Oct 2020 12:28:02 +0100
Subject: [PATCH] Initial QUIC and HTTP/3 implementation using quiche
@@ -14,7 +14,7 @@ Subject: [PATCH] Initial QUIC and HTTP/3 implementation using quiche
auto/options | 9 +
src/core/ngx_connection.h | 7 +
src/core/ngx_core.h | 3 +
- src/event/ngx_event_quic.c | 604 +++++++
+ src/event/ngx_event_quic.c | 618 +++++++
src/event/ngx_event_quic.h | 49 +
src/event/ngx_event_udp.c | 8 +
src/http/modules/ngx_http_ssl_module.c | 13 +-
@@ -32,7 +32,7 @@ Subject: [PATCH] Initial QUIC and HTTP/3 implementation using quiche
src/http/v3/ngx_http_v3_module.c | 286 +++
src/http/v3/ngx_http_v3_module.h | 34 +
src/os/unix/ngx_udp_sendmsg_chain.c | 1 +
- 28 files changed, 3690 insertions(+), 11 deletions(-)
+ 28 files changed, 3704 insertions(+), 11 deletions(-)
create mode 100644 auto/lib/quiche/conf
create mode 100644 auto/lib/quiche/make
create mode 100644 src/event/ngx_event_quic.c
@@ -340,10 +340,10 @@ index 93ca9174d..d0441f034 100644
#include <ngx_module.h>
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
new file mode 100644
-index 000000000..aa7e8e697
+index 000000000..6172e5be3
--- /dev/null
+++ b/src/event/ngx_event_quic.c
-@@ -0,0 +1,604 @@
+@@ -0,0 +1,618 @@
+
+/*
+ * Copyright (C) Cloudflare, Inc.
@@ -518,7 +518,8 @@ index 000000000..aa7e8e697
+ }
+#endif
+
-+ conn = quiche_conn_new_with_tls(scid, sizeof(scid), NULL, 0, quic->config,
++ conn = quiche_conn_new_with_tls(scid, sizeof(scid), NULL, 0,
++ c->sockaddr, c->socklen, quic->config,
+ c->ssl->connection, true);
+ if (conn == NULL) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to create quic connection");
@@ -548,12 +549,17 @@ index 000000000..aa7e8e697
+ size_t buf_len;
+ ssize_t done;
+
++ quiche_recv_info recv_info = {
++ c->sockaddr,
++ c->socklen,
++ };
++
+ /* Process the client's Initial packet, which was saved into c->buffer by
+ * ngx_event_recvmsg(). */
+ buf = c->buffer->pos;
+ buf_len = ngx_buf_size(c->buffer);
+
-+ done = quiche_conn_recv(c->quic->conn, buf, buf_len);
++ done = quiche_conn_recv(c->quic->conn, buf, buf_len, &recv_info);
+
+ if ((done < 0) && (done != QUICHE_ERR_DONE)) {
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -605,7 +611,12 @@ index 000000000..aa7e8e697
+ return;
+ }
+
-+ ssize_t done = quiche_conn_recv(c->quic->conn, buf, n);
++ quiche_recv_info recv_info = {
++ c->sockaddr,
++ c->socklen,
++ };
++
++ ssize_t done = quiche_conn_recv(c->quic->conn, buf, n, &recv_info);
+
+ if (done == QUICHE_ERR_DONE) {
+ break;
@@ -644,6 +655,7 @@ index 000000000..aa7e8e697
+ngx_quic_write_handler(ngx_event_t *wev)
+{
+ ngx_connection_t *c;
++ quiche_send_info send_info;
+ static uint8_t out[MAX_DATAGRAM_SIZE];
+
+ c = wev->data;
@@ -667,7 +679,8 @@ index 000000000..aa7e8e697
+ }
+
+ for (;;) {
-+ ssize_t written = quiche_conn_send(c->quic->conn, out, sizeof(out));
++ ssize_t written = quiche_conn_send(c->quic->conn, out, sizeof(out),
++ &send_info);
+
+ if (written == QUICHE_ERR_DONE) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic done writing");
@@ -787,8 +800,9 @@ index 000000000..aa7e8e697
+ngx_int_t
+ngx_quic_shutdown(ngx_connection_t *c)
+{
-+ ssize_t written;
-+ static uint8_t out[MAX_DATAGRAM_SIZE];
++ ssize_t written;
++ quiche_send_info send_info;
++ static uint8_t out[MAX_DATAGRAM_SIZE];
+
+ /* Connection is closed, free memory. */
+ if (quiche_conn_is_closed(c->quic->conn)) {
@@ -813,7 +827,7 @@ index 000000000..aa7e8e697
+ /* Try sending a packet in order to flush pending frames (CONNECTION_CLOSE
+ * for example), but ignore errors as we are already closing the connection
+ * anyway. */
-+ written = quiche_conn_send(c->quic->conn, out, sizeof(out));
++ written = quiche_conn_send(c->quic->conn, out, sizeof(out), &send_info);
+
+ if (written > 0) {
+ ngx_quic_send_udp_packet(c, out, written);
@@ -4293,5 +4307,5 @@ index 5399c7916..9b03ca536 100644
"sendmsg() not ready");
return NGX_AGAIN;
--
-2.30.2
+2.31.1
diff --git a/fuzz/src/packet_recv_client.rs b/fuzz/src/packet_recv_client.rs
index 84ea7be8..2823abd2 100644
--- a/fuzz/src/packet_recv_client.rs
+++ b/fuzz/src/packet_recv_client.rs
@@ -6,6 +6,8 @@ extern crate libfuzzer_sys;
#[macro_use]
extern crate lazy_static;
+use std::net::SocketAddr;
+
use std::sync::Mutex;
lazy_static! {
@@ -30,10 +32,19 @@ static SCID: quiche::ConnectionId<'static> =
quiche::ConnectionId::from_ref(&[0; quiche::MAX_CONN_ID_LEN]);
fuzz_target!(|data: &[u8]| {
+ let from: SocketAddr = "127.0.0.1:1234".parse().unwrap();
+
let mut buf = data.to_vec();
- let mut conn =
- quiche::connect(Some("quic.tech"), &SCID, &mut CONFIG.lock().unwrap())
- .unwrap();
- conn.recv(&mut buf).ok();
+ let mut conn = quiche::connect(
+ Some("quic.tech"),
+ &SCID,
+ from.clone(),
+ &mut CONFIG.lock().unwrap(),
+ )
+ .unwrap();
+
+ let info = quiche::RecvInfo { from };
+
+ conn.recv(&mut buf, info).ok();
});
diff --git a/fuzz/src/packet_recv_server.rs b/fuzz/src/packet_recv_server.rs
index 671a4631..7749ee7c 100644
--- a/fuzz/src/packet_recv_server.rs
+++ b/fuzz/src/packet_recv_server.rs
@@ -6,6 +6,8 @@ extern crate libfuzzer_sys;
#[macro_use]
extern crate lazy_static;
+use std::net::SocketAddr;
+
use std::sync::Mutex;
lazy_static! {
@@ -36,9 +38,14 @@ static SCID: quiche::ConnectionId<'static> =
quiche::ConnectionId::from_ref(&[0; quiche::MAX_CONN_ID_LEN]);
fuzz_target!(|data: &[u8]| {
+ let from: SocketAddr = "127.0.0.1:1234".parse().unwrap();
+
let mut buf = data.to_vec();
+
let mut conn =
- quiche::accept(&SCID, None, &mut CONFIG.lock().unwrap()).unwrap();
+ quiche::accept(&SCID, None, from, &mut CONFIG.lock().unwrap()).unwrap();
+
+ let info = quiche::RecvInfo { from };
- conn.recv(&mut buf).ok();
+ conn.recv(&mut buf, info).ok();
});
diff --git a/include/quiche.h b/include/quiche.h
index d22e8171..2f316242 100644
--- a/include/quiche.h
+++ b/include/quiche.h
@@ -216,11 +216,14 @@ typedef struct Connection quiche_conn;
// Creates a new server-side connection.
quiche_conn *quiche_accept(const uint8_t *scid, size_t scid_len,
const uint8_t *odcid, size_t odcid_len,
+ const struct sockaddr *from, size_t from_len,
quiche_config *config);
// Creates a new client-side connection.
-quiche_conn *quiche_connect(const char *server_name, const uint8_t *scid,
- size_t scid_len, quiche_config *config);
+quiche_conn *quiche_connect(const char *server_name,
+ const uint8_t *scid, size_t scid_len,
+ const struct sockaddr *to, size_t to_len,
+ quiche_config *config);
// Writes a version negotiation packet.
ssize_t quiche_negotiate_version(const uint8_t *scid, size_t scid_len,
@@ -239,6 +242,7 @@ bool quiche_version_is_supported(uint32_t version);
quiche_conn *quiche_conn_new_with_tls(const uint8_t *scid, size_t scid_len,
const uint8_t *odcid, size_t odcid_len,
+ const struct sockaddr *peer, size_t peer_len,
quiche_config *config, void *ssl,
bool is_server);
@@ -259,11 +263,23 @@ void quiche_conn_set_qlog_fd(quiche_conn *conn, int fd, const char *log_title,
// Configures the given session for resumption.
int quiche_conn_set_session(quiche_conn *conn, const uint8_t *buf, size_t buf_len);
+typedef struct {
+ struct sockaddr *from;
+ socklen_t from_len;
+} quiche_recv_info;
+
// Processes QUIC packets received from the peer.
-ssize_t quiche_conn_recv(quiche_conn *conn, uint8_t *buf, size_t buf_len);
+ssize_t quiche_conn_recv(quiche_conn *conn, uint8_t *buf, size_t buf_len,
+ const quiche_recv_info *info);
+
+typedef struct {
+ struct sockaddr_storage to;
+ socklen_t to_len;
+} quiche_send_info;
// Writes a single QUIC packet to be sent to the peer.
-ssize_t quiche_conn_send(quiche_conn *conn, uint8_t *out, size_t out_len);
+ssize_t quiche_conn_send(quiche_conn *conn, uint8_t *out, size_t out_len,
+ quiche_send_info *out_info);
// Reads contiguous data from a stream.
ssize_t quiche_conn_stream_recv(quiche_conn *conn, uint64_t stream_id,
diff --git a/src/ffi.rs b/src/ffi.rs
index fda2a37a..04965be9 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -29,6 +29,8 @@ use std::ptr;
use std::slice;
use std::sync::atomic;
+use std::net::SocketAddr;
+
#[cfg(unix)]
use std::os::unix::io::FromRawFd;
@@ -36,8 +38,39 @@ use libc::c_char;
use libc::c_int;
use libc::c_void;
use libc::size_t;
+use libc::sockaddr;
use libc::ssize_t;
+#[cfg(not(windows))]
+use libc::sockaddr_in;
+#[cfg(windows)]
+use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in;
+
+#[cfg(not(windows))]
+use libc::sockaddr_in6;
+#[cfg(windows)]
+use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
+
+#[cfg(not(windows))]
+use libc::sockaddr_storage;
+#[cfg(windows)]
+use winapi::shared::ws2def::SOCKADDR_STORAGE_LH as sockaddr_storage;
+
+#[cfg(windows)]
+use libc::c_int as socklen_t;
+#[cfg(not(windows))]
+use libc::socklen_t;
+
+#[cfg(not(windows))]
+use libc::AF_INET;
+#[cfg(windows)]
+use winapi::shared::ws2def::AF_INET;
+
+#[cfg(not(windows))]
+use libc::AF_INET6;
+#[cfg(windows)]
+use winapi::shared::ws2def::AF_INET6;
+
use crate::*;
#[no_mangle]
@@ -342,7 +375,7 @@ pub extern fn quiche_header_info(
#[no_mangle]
pub extern fn quiche_accept(
scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
- config: &mut Config,
+ from: &sockaddr, from_len: socklen_t, config: &mut Config,
) -> *mut Connection {
let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
let scid = ConnectionId::from_ref(scid);
@@ -355,7 +388,9 @@ pub extern fn quiche_accept(
None
};
- match accept(&scid, odcid.as_ref(), config) {
+ let from = std_addr_from_c(from, from_len);
+
+ match accept(&scid, odcid.as_ref(), from, config) {
Ok(c) => Box::into_raw(Pin::into_inner(c)),
Err(_) => ptr::null_mut(),
@@ -364,8 +399,8 @@ pub extern fn quiche_accept(
#[no_mangle]
pub extern fn quiche_connect(
- server_name: *const c_char, scid: *const u8, scid_len: size_t,
- config: &mut Config,
+ server_name: *const c_char, scid: *const u8, scid_len: size_t, to: &sockaddr,
+ to_len: socklen_t, config: &mut Config,
) -> *mut Connection {
let server_name = if server_name.is_null() {
None
@@ -376,7 +411,9 @@ pub extern fn quiche_connect(
let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
let scid = ConnectionId::from_ref(scid);
- match connect(server_name, &scid, config) {
+ let to = std_addr_from_c(to, to_len);
+
+ match connect(server_name, &scid, to, config) {
Ok(c) => Box::into_raw(Pin::into_inner(c)),
Err(_) => ptr::null_mut(),
@@ -436,7 +473,8 @@ pub extern fn quiche_retry(
#[no_mangle]
pub extern fn quiche_conn_new_with_tls(
scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
- config: &mut Config, ssl: *mut c_void, is_server: bool,
+ peer: &sockaddr, peer_len: socklen_t, config: &mut Config, ssl: *mut c_void,
+ is_server: bool,
) -> *mut Connection {
let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
let scid = ConnectionId::from_ref(scid);
@@ -449,9 +487,18 @@ pub extern fn quiche_conn_new_with_tls(
None
};
+ let peer = std_addr_from_c(peer, peer_len);
+
let tls = unsafe { tls::Handshake::from_ptr(ssl) };
- match Connection::with_tls(&scid, odcid.as_ref(), config, tls, is_server) {
+ match Connection::with_tls(
+ &scid,
+ odcid.as_ref(),
+ peer,
+ config,
+ tls,
+ is_server,
+ ) {
Ok(c) => Box::into_raw(Pin::into_inner(c)),
Err(_) => ptr::null_mut(),
@@ -552,9 +599,23 @@ pub extern fn quiche_conn_set_session(
}
}
+#[repr(C)]
+pub struct RecvInfo<'a> {
+ from: &'a sockaddr,
+ from_len: socklen_t,
+}
+
+impl<'a> From<&RecvInfo<'a>> for crate::RecvInfo {
+ fn from(info: &RecvInfo) -> crate::RecvInfo {
+ crate::RecvInfo {
+ from: std_addr_from_c(info.from, info.from_len),
+ }
+ }
+}
+
#[no_mangle]
pub extern fn quiche_conn_recv(
- conn: &mut Connection, buf: *mut u8, buf_len: size_t,
+ conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo,
) -> ssize_t {
if buf_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
@@ -562,16 +623,22 @@ pub extern fn quiche_conn_recv(
let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
- match conn.recv(buf) {
+ match conn.recv(buf, info.into()) {
Ok(v) => v as ssize_t,
Err(e) => e.to_c(),
}
}
+#[repr(C)]
+pub struct SendInfo {
+ to: sockaddr_storage,
+ to_len: socklen_t,
+}
+
#[no_mangle]
pub extern fn quiche_conn_send(
- conn: &mut Connection, out: *mut u8, out_len: size_t,
+ conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo,
) -> ssize_t {
if out_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
@@ -580,7 +647,11 @@ pub extern fn quiche_conn_send(
let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
match conn.send(out) {
- Ok(v) => v as ssize_t,
+ Ok((v, info)) => {
+ out_info.to_len = std_addr_to_c(&info.to, &mut out_info.to);
+
+ v as ssize_t
+ },
Err(e) => e.to_c(),
}
@@ -869,12 +940,12 @@ pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
#[repr(C)]
pub struct Stats {
- pub recv: usize,
- pub sent: usize,
- pub lost: usize,
- pub rtt: u64,
- pub cwnd: usize,
- pub delivery_rate: u64,
+ recv: usize,
+ sent: usize,
+ lost: usize,
+ rtt: u64,
+ cwnd: usize,
+ delivery_rate: u64,
}
#[no_mangle]
@@ -969,3 +1040,55 @@ pub extern fn quiche_conn_peer_streams_left_bidi(conn: &mut Connection) -> u64 {
pub extern fn quiche_conn_peer_streams_left_uni(conn: &mut Connection) -> u64 {
conn.peer_streams_left_uni()
}
+
+fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
+ unsafe {
+ match addr.sa_family as i32 {
+ AF_INET => {
+ assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
+
+ SocketAddr::V4(
+ *(addr as *const _ as *const sockaddr_in as *const _),
+ )
+ },
+
+ AF_INET6 => {
+ assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
+
+ SocketAddr::V6(
+ *(addr as *const _ as *const sockaddr_in6 as *const _),
+ )
+ },
+
+ _ => unimplemented!("unsupported address type"),
+ }
+ }
+}
+
+fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
+ unsafe {
+ match addr {
+ SocketAddr::V4(addr) => {
+ let sa_len = std::mem::size_of::<sockaddr_in>();
+
+ let src = addr as *const _ as *const u8;
+ let dst = out as *mut _ as *mut u8;
+
+ std::ptr::copy_nonoverlapping(src, dst, sa_len);
+
+ sa_len as socklen_t
+ },
+
+ SocketAddr::V6(addr) => {
+ let sa_len = std::mem::size_of::<sockaddr_in6>();
+
+ let src = addr as *const _ as *const u8;
+ let dst = out as *mut _ as *mut u8;
+
+ std::ptr::copy_nonoverlapping(src, dst, sa_len);
+
+ sa_len as socklen_t
+ },
+ }
+ }
+}
diff --git a/src/h3/mod.rs b/src/h3/mod.rs
index beef46bc..60fd3af8 100644
--- a/src/h3/mod.rs
+++ b/src/h3/mod.rs
@@ -60,7 +60,8 @@
//! ```no_run
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config).unwrap();
//! # let h3_config = quiche::h3::Config::new()?;
//! let h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! # Ok::<(), quiche::h3::Error>(())
@@ -75,7 +76,8 @@
//! ```no_run
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let to = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::connect(None, &scid, to, &mut config).unwrap();
//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! let req = vec![
@@ -96,7 +98,8 @@
//! ```no_run
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let to = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::connect(None, &scid, to, &mut config).unwrap();
//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! let req = vec![
@@ -126,7 +129,8 @@
//!
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config).unwrap();
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config).unwrap();
//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! loop {
@@ -187,7 +191,8 @@
//!
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let to = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::connect(None, &scid, to, &mut config).unwrap();
//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! loop {
diff --git a/src/lib.rs b/src/lib.rs
index 8574b4d3..c6622a7f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -55,14 +55,24 @@
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let server_name = "quic.tech";
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
+//! # let to = "127.0.0.1:1234".parse().unwrap();
//! // Client connection.
-//! let conn = quiche::connect(Some(&server_name), &scid, &mut config)?;
+//! let conn = quiche::connect(Some(&server_name), &scid, to, &mut config)?;
//!
//! // Server connection.
-//! let conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! let conn = quiche::accept(&scid, None, from, &mut config)?;
//! # Ok::<(), quiche::Error>(())
//! ```
//!
+//! In both cases, the application is responsible for generating a new source
+//! connection ID that will be used to identify the new connection.
+//!
+//! The application also need to pass the address of the remote peer of the
+//! connection: in the case of a client that would be the address of the server
+//! it is trying to connect to, and for a server that is the address of the
+//! client that initiated the connection.
+//!
//! ## Handling incoming packets
//!
//! Using the connection's [`recv()`] method the application can process
@@ -73,11 +83,14 @@
//! # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
//! loop {
-//! let read = socket.recv(&mut buf).unwrap();
+//! let (read, from) = socket.recv_from(&mut buf).unwrap();
+//!
+//! let recv_info = quiche::RecvInfo { from };
//!
-//! let read = match conn.recv(&mut buf[..read]) {
+//! let read = match conn.recv(&mut buf[..read], recv_info) {
//! Ok(v) => v,
//!
//! Err(quiche::Error::Done) => {
@@ -94,6 +107,10 @@
//! # Ok::<(), quiche::Error>(())
//! ```
//!
+//! The application has to pass a [`RecvInfo`] structure in order to provide
+//! additional information about the received packet (such as the address it
+//! was received from).
+//!
//! ## Generating outgoing packets
//!
//! Outgoing packet are generated using the connection's [`send()`] method
@@ -104,9 +121,10 @@
//! # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
//! loop {
-//! let write = match conn.send(&mut out) {
+//! let (write, send_info) = match conn.send(&mut out) {
//! Ok(v) => v,
//!
//! Err(quiche::Error::Done) => {
@@ -120,11 +138,15 @@
//! },
//! };
//!
-//! socket.send(&out[..write]).unwrap();
+//! socket.send_to(&out[..write], &send_info.to).unwrap();
//! }
//! # Ok::<(), quiche::Error>(())
//! ```
//!
+//! The application will be provided with a [`SendInfo`] structure providing
+//! additional information about the newly created packet (such as the address
+//! the packet should be sent to).
+//!
//! When packets are sent, the application is responsible for maintaining a
//! timer to react to time-based connection events. The timer expiration can be
//! obtained using the connection's [`timeout()`] method.
@@ -132,7 +154,8 @@
//! ```
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
//! let timeout = conn.timeout();
//! # Ok::<(), quiche::Error>(())
//! ```
@@ -147,13 +170,14 @@
//! # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
//! // Timeout expired, handle it.
//! conn.on_timeout();
//!
//! // Send more packets as needed after timeout.
//! loop {
-//! let write = match conn.send(&mut out) {
+//! let (write, send_info) = match conn.send(&mut out) {
//! Ok(v) => v,
//!
//! Err(quiche::Error::Done) => {
@@ -167,7 +191,7 @@
//! },
//! };
//!
-//! socket.send(&out[..write]).unwrap();
+//! socket.send_to(&out[..write], &send_info.to).unwrap();
//! }
//! # Ok::<(), quiche::Error>(())
//! ```
@@ -182,7 +206,8 @@
//! ```no_run
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
//! if conn.is_established() {
//! // Handshake completed, send some data on stream 0.
//! conn.stream_send(0, b"hello", true)?;
@@ -201,7 +226,8 @@
//! # let mut buf = [0; 512];
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
//! # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
+//! # let from = "127.0.0.1:1234".parse().unwrap();
+//! # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
//! if conn.is_established() {
//! // Iterate over readable streams.
//! for stream_id in conn.readable() {
@@ -222,7 +248,9 @@
//! [`connect()`]: fn.connect.html
//! [`accept()`]: fn.accept.html
//! [`recv()`]: struct.Connection.html#method.recv
+//! [`RecvInfo`]: struct.RecvInfo.html
//! [`send()`]: struct.Connection.html#method.send
+//! [`SendInfo`]: struct.SendInfo.html
//! [`timeout()`]: struct.Connection.html#method.timeout
//! [`on_timeout()`]: struct.Connection.html#method.on_timeout
//! [`stream_send()`]: struct.Connection.html#method.stream_send
@@ -270,6 +298,8 @@ extern crate log;
use std::cmp;
use std::time;
+use std::net::SocketAddr;
+
use std::pin::Pin;
use std::str::FromStr;
@@ -448,6 +478,20 @@ impl std::convert::From<octets::BufferTooShortError> for Error {
}
}
+/// Ancillary information about incoming packets.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct RecvInfo {
+ /// The address the packet was received from.
+ pub from: SocketAddr,
+}
+
+/// Ancillary information about outgoing packets.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct SendInfo {
+ /// The address the packet should be sent to.
+ pub to: SocketAddr,
+}
+
/// Represents information carried by `CONNECTION_CLOSE` frames.
#[derive(Clone, Debug, PartialEq)]
pub struct ConnectionError {
@@ -913,6 +957,8 @@ pub struct Connection {
/// Loss recovery and congestion control state.
recovery: recovery::Recovery,
+ peer_addr: SocketAddr,
+
/// List of supported application protocols.
application_protos: Vec<Vec<u8>>,
@@ -983,7 +1029,7 @@ pub struct Connection {
draining_timer: Option<time::Instant>,
/// List of raw packets that were received before they could be decrypted.
- undecryptable_pkts: VecDeque<Vec<u8>>,
+ undecryptable_pkts: VecDeque<(Vec<u8>, RecvInfo)>,
/// The negotiated ALPN protocol.
alpn: Vec<u8>,
@@ -1062,14 +1108,16 @@ pub struct Connection {
/// ```no_run
/// # let mut config = quiche::Config::new(0xbabababa)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-/// let conn = quiche::accept(&scid, None, &mut config)?;
+/// # let from = "127.0.0.1:1234".parse().unwrap();
+/// let conn = quiche::accept(&scid, None, from, &mut config)?;
/// # Ok::<(), quiche::Error>(())
/// ```
#[inline]
pub fn accept(
- scid: &ConnectionId, odcid: Option<&ConnectionId>, config: &mut Config,
+ scid: &ConnectionId, odcid: Option<&ConnectionId>, from: SocketAddr,
+ config: &mut Config,
) -> Result<Pin<Box<Connection>>> {
- let conn = Connection::new(scid, odcid, config, true)?;
+ let conn = Connection::new(scid, odcid, from, config, true)?;
Ok(conn)
}
@@ -1086,14 +1134,16 @@ pub fn accept(
/// # let mut config = quiche::Config::new(0xbabababa)?;
/// # let server_name = "quic.tech";
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
-/// let conn = quiche::connect(Some(&server_name), &scid, &mut config)?;
+/// # let to = "127.0.0.1:1234".parse().unwrap();
+/// let conn = quiche::connect(Some(&server_name), &scid, to, &mut config)?;
/// # Ok::<(), quiche::Error>(())
/// ```
#[inline]
pub fn connect(
- server_name: Option<&str>, scid: &ConnectionId, config: &mut Config,
+ server_name: Option<&str>, scid: &ConnectionId, to: SocketAddr,
+ config: &mut Config,
) -> Result<Pin<Box<Connection>>> {
- let conn = Connection::new(scid, None, config, false)?;
+ let conn = Connection::new(scid, None, to, config, false)?;
if let Some(server_name) = server_name {
conn.handshake.lock().unwrap().set_host_name(server_name)?;
@@ -1187,7 +1237,7 @@ pub fn negotiate_version(
/// return Ok(());
/// }
///
-/// let conn = quiche::accept(&scid, odcid.as_ref(), &mut config)?;
+/// let conn = quiche::accept(&scid, odcid.as_ref(), src, &mut config)?;
/// # Ok::<(), quiche::Error>(())
/// ```
#[inline]
@@ -1248,16 +1298,16 @@ macro_rules! qlog_with {
impl Connection {
fn new(
- scid: &ConnectionId, odcid: Option<&ConnectionId>, config: &mut Config,
- is_server: bool,
+ scid: &ConnectionId, odcid: Option<&ConnectionId>, peer: SocketAddr,
+ config: &mut Config, is_server: bool,
) -> Result<Pin<Box<Connection>>> {
let tls = config.tls_ctx.lock().unwrap().new_handshake()?;
- Connection::with_tls(scid, odcid, config, tls, is_server)
+ Connection::with_tls(scid, odcid, peer, config, tls, is_server)
}
fn with_tls(
- scid: &ConnectionId, odcid: Option<&ConnectionId>, config: &mut Config,
- tls: tls::Handshake, is_server: bool,
+ scid: &ConnectionId, odcid: Option<&ConnectionId>, peer: SocketAddr,
+ config: &mut Config, tls: tls::Handshake, is_server: bool,
) -> Result<Pin<Box<Connection>>> {
let max_rx_data = config.local_transport_params.initial_max_data;
@@ -1288,6 +1338,8 @@ impl Connection {
recovery: recovery::Recovery::new(&config),
+ peer_addr: peer,
+
application_protos: config.application_protos.clone(),
recv_count: 0,
@@ -1548,11 +1600,14 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// loop {
- /// let read = socket.recv(&mut buf).unwrap();
+ /// let (read, from) = socket.recv_from(&mut buf).unwrap();
+ ///
+ /// let recv_info = quiche::RecvInfo { from };
///
- /// let read = match conn.recv(&mut buf[..read]) {
+ /// let read = match conn.recv(&mut buf[..read], recv_info) {
/// Ok(v) => v,
///
/// Err(e) => {
@@ -1563,7 +1618,7 @@ impl Connection {
/// }
/// # Ok::<(), quiche::Error>(())
/// ```
- pub fn recv(&mut self, buf: &mut [u8]) -> Result<usize> {
+ pub fn recv(&mut self, buf: &mut [u8], info: RecvInfo) -> Result<usize> {
let len = buf.len();
if len == 0 {
@@ -1586,7 +1641,7 @@ impl Connection {
// Process coalesced packets.
while left > 0 {
- let read = match self.recv_single(&mut buf[len - left..len]) {
+ let read = match self.recv_single(&mut buf[len - left..len], &info) {
Ok(v) => v,
Err(Error::Done) => left,
@@ -1609,8 +1664,9 @@ impl Connection {
.crypto_0rtt_open
.is_some()
{
- while let Some(mut pkt) = self.undecryptable_pkts.pop_front() {
- if let Err(e) = self.recv(&mut pkt) {
+ while let Some((mut pkt, info)) = self.undecryptable_pkts.pop_front()
+ {
+ if let Err(e) = self.recv(&mut pkt, info) {
self.undecryptable_pkts.clear();
// Even though the packet was previously "accepted", it
@@ -1633,7 +1689,7 @@ impl Connection {
/// On error, an error other than [`Done`] is returned.
///
/// [`Done`]: enum.Error.html#variant.Done
- fn recv_single(&mut self, buf: &mut [u8]) -> Result<usize> {
+ fn recv_single(&mut self, buf: &mut [u8], info: &RecvInfo) -> Result<usize> {
let now = time::Instant::now();
if buf.is_empty() {
@@ -1901,7 +1957,7 @@ impl Connection {
let pkt_len = b.off() + payload_len;
let pkt = (b.buf()[..pkt_len]).to_vec();
- self.undecryptable_pkts.push_back(pkt);
+ self.undecryptable_pkts.push_back((pkt, *info));
return Ok(pkt_len);
}
@@ -2210,9 +2266,10 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// loop {
- /// let write = match conn.send(&mut out) {
+ /// let (write, send_info) = match conn.send(&mut out) {
/// Ok(v) => v,
///
/// Err(quiche::Error::Done) => {
@@ -2226,11 +2283,11 @@ impl Connection {
/// },
/// };
///
- /// socket.send(&out[..write]).unwrap();
+ /// socket.send_to(&out[..write], &send_info.to).unwrap();
/// }
/// # Ok::<(), quiche::Error>(())
/// ```
- pub fn send(&mut self, out: &mut [u8]) -> Result<usize> {
+ pub fn send(&mut self, out: &mut [u8]) -> Result<(usize, SendInfo)> {
if out.is_empty() {
return Err(Error::BufferTooShort);
}
@@ -2249,8 +2306,9 @@ impl Connection {
.crypto_0rtt_open
.is_some()
{
- while let Some(mut pkt) = self.undecryptable_pkts.pop_front() {
- if self.recv(&mut pkt).is_err() {
+ while let Some((mut pkt, info)) = self.undecryptable_pkts.pop_front()
+ {
+ if self.recv(&mut pkt, info).is_err() {
self.undecryptable_pkts.clear();
// Forwarding the error value here could confuse
@@ -2332,7 +2390,9 @@ impl Connection {
done += pad_len;
}
- Ok(done)
+ let info = SendInfo { to: self.peer_addr };
+
+ Ok((done, info))
}
fn send_single(
@@ -3162,7 +3222,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// # let stream_id = 0;
/// while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) {
/// println!("Got {} bytes on stream {}", read, stream_id);
@@ -3267,7 +3328,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// # let stream_id = 0;
/// conn.stream_send(stream_id, b"hello", true)?;
/// # Ok::<(), quiche::Error>(())
@@ -3584,7 +3646,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// // Iterate over readable streams.
/// for stream_id in conn.readable() {
/// // Stream is readable, read until there's no more data.
@@ -3618,7 +3681,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// // Iterate over writable streams.
/// for stream_id in conn.writable() {
/// // Stream is writable, write some data.
@@ -3683,7 +3747,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// let mut dgram_buf = [0; 512];
/// while let Ok((len)) = conn.dgram_recv(&mut dgram_buf) {
/// println!("Got {} bytes of DATAGRAM", len);
@@ -3756,7 +3821,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// conn.dgram_send(b"hello")?;
/// # Ok::<(), quiche::Error>(())
/// ```
@@ -3790,7 +3856,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// conn.dgram_send(b"hello")?;
/// conn.dgram_purge_outgoing(&|d: &[u8]| -> bool { d[0] == 0 });
/// # Ok::<(), quiche::Error>(())
@@ -3812,7 +3879,8 @@ impl Connection {
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = quiche::ConnectionId::from_ref(&[0xba; 16]);
- /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// # let from = "127.0.0.1:1234".parse().unwrap();
+ /// # let mut conn = quiche::accept(&scid, None, from, &mut config)?;
/// if let Some(payload_size) = conn.dgram_max_writable_len() {
/// if payload_size > 5 {
/// conn.dgram_send(b"hello")?;
@@ -5296,14 +5364,21 @@ pub mod testing {
let mut client_scid = [0; 16];
rand::rand_bytes(&mut client_scid[..]);
let client_scid = ConnectionId::from_ref(&client_scid);
+ let client_addr = "127.0.0.1:1234".parse().unwrap();
let mut server_scid = [0; 16];
rand::rand_bytes(&mut server_scid[..]);
let server_scid = ConnectionId::from_ref(&server_scid);
+ let server_addr = "127.0.0.1:4321".parse().unwrap();
Ok(Pipe {
- client: connect(Some("quic.tech"), &client_scid, config)?,
- server: accept(&server_scid, None, config)?,
+ client: connect(
+ Some("quic.tech"),
+ &client_scid,
+ client_addr,
+ config,
+ )?,
+ server: accept(&server_scid, None, server_addr, config)?,
})
}
@@ -5311,10 +5386,12 @@ pub mod testing {
let mut client_scid = [0; 16];
rand::rand_bytes(&mut client_scid[..]);
let client_scid = ConnectionId::from_ref(&client_scid);
+ let client_addr = "127.0.0.1:1234".parse().unwrap();
let mut server_scid = [0; 16];
rand::rand_bytes(&mut server_scid[..]);
let server_scid = ConnectionId::from_ref(&server_scid);
+ let server_addr = "127.0.0.1:4321".parse().unwrap();
let mut config = Config::new(crate::PROTOCOL_VERSION)?;
config.load_cert_chain_from_pem_file("examples/cert.crt")?;
@@ -5327,8 +5404,13 @@ pub mod testing {
config.set_initial_max_streams_uni(3);
Ok(Pipe {
- client: connect(Some("quic.tech"), &client_scid, client_config)?,
- server: accept(&server_scid, None, &mut config)?,
+ client: connect(
+ Some("quic.tech"),
+ &client_scid,
+ client_addr,
+ client_config,
+ )?,
+ server: accept(&server_scid, None, server_addr, &mut config)?,
})
}
@@ -5336,10 +5418,12 @@ pub mod testing {
let mut client_scid = [0; 16];
rand::rand_bytes(&mut client_scid[..]);
let client_scid = ConnectionId::from_ref(&client_scid);
+ let client_addr = "127.0.0.1:1234".parse().unwrap();
let mut server_scid = [0; 16];
rand::rand_bytes(&mut server_scid[..]);
let server_scid = ConnectionId::from_ref(&server_scid);
+ let server_addr = "127.0.0.1:4321".parse().unwrap();
let mut config = Config::new(crate::PROTOCOL_VERSION)?;
config.set_application_protos(b"\x06proto1\x06proto2")?;
@@ -5350,8 +5434,13 @@ pub mod testing {
config.set_initial_max_streams_uni(3);
Ok(Pipe {
- client: connect(Some("quic.tech"), &client_scid, &mut config)?,
- server: accept(&server_scid, None, server_config)?,
+ client: connect(
+ Some("quic.tech"),
+ &client_scid,
+ client_addr,
+ &mut config,
+ )?,
+ server: accept(&server_scid, None, server_addr, server_config)?,
})
}
@@ -5392,6 +5481,22 @@ pub mod testing {
Ok(())
}
+ pub fn client_recv(&mut self, buf: &mut [u8]) -> Result<usize> {
+ let info = RecvInfo {
+ from: self.client.peer_addr,
+ };
+
+ self.client.recv(buf, info)
+ }
+
+ pub fn server_recv(&mut self, buf: &mut [u8]) -> Result<usize> {
+ let info = RecvInfo {
+ from: self.server.peer_addr,
+ };
+
+ self.server.recv(buf, info)
+ }
+
pub fn send_pkt_to_server(
&mut self, pkt_type: packet::Type, frames: &[frame::Frame],
buf: &mut [u8],
@@ -5404,12 +5509,16 @@ pub mod testing {
pub fn recv_send(
conn: &mut Connection, buf: &mut [u8], len: usize,
) -> Result<usize> {
- conn.recv(&mut buf[..len])?;
+ let info = RecvInfo {
+ from: conn.peer_addr,
+ };
+
+ conn.recv(&mut buf[..len], info)?;
let mut off = 0;
match conn.send(&mut buf[off..]) {
- Ok(write) => off += write,
+ Ok((write, _)) => off += write,
Err(Error::Done) => (),
@@ -5423,7 +5532,11 @@ pub mod testing {
conn: &mut Connection, flight: Vec<Vec<u8>>,
) -> Result<()> {
for mut pkt in flight {
- conn.recv(&mut pkt)?;
+ let info = RecvInfo {
+ from: conn.peer_addr,
+ };
+
+ conn.recv(&mut pkt, info)?;
}
Ok(())
@@ -5436,7 +5549,7 @@ pub mod testing {
let mut out = vec![0u8; 65535];
match conn.send(&mut out) {
- Ok(written) => out.truncate(written),
+ Ok((written, _)) => out.truncate(written),
Err(Error::Done) => break,
@@ -5658,12 +5771,12 @@ mod tests {
let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap();
- let mut len = pipe.client.send(&mut buf).unwrap();
+ let (mut len, _) = pipe.client.send(&mut buf).unwrap();
let hdr = packet::Header::from_slice(&mut buf[..len], 0).unwrap();
len = crate::negotiate_version(&hdr.scid, &hdr.dcid, &mut buf).unwrap();
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
assert_eq!(pipe.handshake(), Ok(()));
@@ -5699,11 +5812,11 @@ mod tests {
assert_eq!(pipe.client.encode_transport_params(), Ok(()));
// Client sends initial flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
// Server rejects transport parameters.
assert_eq!(
- pipe.server.recv(&mut buf[..len]),
+ pipe.server_recv(&mut buf[..len]),
Err(Error::InvalidTransportParam)
);
}
@@ -5721,11 +5834,11 @@ mod tests {
assert_eq!(pipe.client.encode_transport_params(), Ok(()));
// Client sends initial flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
// Server rejects transport parameters.
assert_eq!(
- pipe.server.recv(&mut buf[..len]),
+ pipe.server_recv(&mut buf[..len]),
Err(Error::InvalidTransportParam)
);
}
@@ -5897,7 +6010,9 @@ mod tests {
assert_eq!(pipe.server.application_proto(), b"");
// Server should only send one packet in response to ALPN mismatch.
- assert_eq!(pipe.server.send(&mut buf), Ok(1200));
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
+ assert_eq!(len, 1200);
+
assert_eq!(pipe.server.send(&mut buf), Err(Error::Done));
assert_eq!(pipe.server.sent_count, 1);
}
@@ -5935,8 +6050,8 @@ mod tests {
assert_eq!(pipe.client.set_session(&session), Ok(()));
// Client sends initial flight.
- let len = pipe.client.send(&mut buf).unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
// Client sends 0-RTT packet.
let pkt_type = packet::Type::ZeroRTT;
@@ -5996,7 +6111,7 @@ mod tests {
assert_eq!(pipe.client.set_session(&session), Ok(()));
// Client sends initial flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let mut initial = (&buf[..len]).to_vec();
// Client sends 0-RTT packet.
@@ -6013,16 +6128,16 @@ mod tests {
let mut zrtt = (&buf[..len]).to_vec();
// 0-RTT packet is received before the Initial one.
- assert_eq!(pipe.server.recv(&mut zrtt), Ok(zrtt.len()));
+ assert_eq!(pipe.server_recv(&mut zrtt), Ok(zrtt.len()));
assert_eq!(pipe.server.undecryptable_pkts.len(), 1);
- assert_eq!(pipe.server.undecryptable_pkts[0].len(), zrtt.len());
+ assert_eq!(pipe.server.undecryptable_pkts[0].0.len(), zrtt.len());
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
// Initial packet is also received.
- assert_eq!(pipe.server.recv(&mut initial), Ok(initial.len()));
+ assert_eq!(pipe.server_recv(&mut initial), Ok(initial.len()));
// 0-RTT stream data is readable.
let mut r = pipe.server.readable();
@@ -6085,7 +6200,7 @@ mod tests {
let mut zrtt = (&buf[..len - 1]).to_vec();
// 0-RTT packet is received before the Initial one.
- assert_eq!(pipe.server.recv(&mut zrtt), Err(Error::InvalidPacket));
+ assert_eq!(pipe.server_recv(&mut zrtt), Err(Error::InvalidPacket));
assert_eq!(pipe.server.undecryptable_pkts.len(), 0);
@@ -6188,7 +6303,7 @@ mod tests {
assert_eq!(pipe.client.set_session(&session), Ok(()));
// Client sends initial flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let mut initial = (&buf[..len]).to_vec();
assert_eq!(pipe.client.is_in_early_data(), true);
@@ -6196,14 +6311,14 @@ mod tests {
// Client sends 0-RTT data.
assert_eq!(pipe.client.stream_send(4, b"hello, world", true), Ok(12));
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let mut zrtt = (&buf[..len]).to_vec();
// Server receives packets.
- assert_eq!(pipe.server.recv(&mut initial), Ok(initial.len()));
+ assert_eq!(pipe.server_recv(&mut initial), Ok(initial.len()));
assert_eq!(pipe.server.is_in_early_data(), true);
- assert_eq!(pipe.server.recv(&mut zrtt), Ok(zrtt.len()));
+ assert_eq!(pipe.server_recv(&mut zrtt), Ok(zrtt.len()));
// 0-RTT stream data is readable.
let mut r = pipe.server.readable();
@@ -6346,7 +6461,7 @@ mod tests {
let written =
testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf)
.unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..written]), Ok(written));
+ assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
assert_eq!(pipe.server.max_send_bytes, 195);
@@ -6989,7 +7104,8 @@ mod tests {
let written =
testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf)
.unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..written]), Ok(written));
+
+ assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
// Send 1-RTT packet #1.
let frames = [frame::Frame::Stream {
@@ -7000,7 +7116,8 @@ mod tests {
let written =
testing::encode_pkt(&mut pipe.client, pkt_type, &frames, &mut buf)
.unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..written]), Ok(written));
+
+ assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
assert!(!pipe.server.is_established());
@@ -7234,7 +7351,7 @@ mod tests {
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
let mut dummy = buf[..len].to_vec();
@@ -7250,7 +7367,7 @@ mod tests {
})
);
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
assert_eq!(pipe.advance(), Ok(()));
@@ -7368,7 +7485,7 @@ mod tests {
let mut r = pipe.server.writable();
assert_eq!(r.next(), None);
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
let mut dummy = buf[..len].to_vec();
@@ -7385,7 +7502,7 @@ mod tests {
})
);
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
assert_eq!(pipe.advance(), Ok(()));
@@ -7429,7 +7546,7 @@ mod tests {
assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5));
assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5));
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
@@ -7447,7 +7564,7 @@ mod tests {
})
);
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
@@ -7460,7 +7577,7 @@ mod tests {
})
);
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
@@ -7670,7 +7787,7 @@ mod tests {
assert_eq!(pipe.server.timeout(), None);
assert_eq!(
- pipe.server.recv(&mut buf[..written]),
+ pipe.server_recv(&mut buf[..written]),
Err(Error::CryptoFail)
);
@@ -7685,10 +7802,10 @@ mod tests {
let mut pipe = testing::Pipe::default().unwrap();
// Client sends initial flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
// Server sends initial flight.
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(1200));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(1200));
let frames = [frame::Frame::Padding { len: 10 }];
@@ -7706,7 +7823,7 @@ mod tests {
buf[written - 1] = !buf[written - 1];
// Client will ignore invalid packet.
- assert_eq!(pipe.client.recv(&mut buf[..written]), Ok(71));
+ assert_eq!(pipe.client_recv(&mut buf[..written]), Ok(71));
// The connection should be alive...
assert_eq!(pipe.client.is_closed(), false);
@@ -7780,7 +7897,7 @@ mod tests {
assert_eq!(pipe.server.timeout(), None);
assert_eq!(
- pipe.server.recv(&mut buf[..written]),
+ pipe.server_recv(&mut buf[..written]),
Err(Error::InvalidPacket)
);
@@ -7810,12 +7927,12 @@ mod tests {
// cannot be authenticated during decryption).
buf[written - 1] = !buf[written - 1];
- assert_eq!(pipe.server.recv(&mut buf[..written]), Ok(written));
+ assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
// Corrupt the packets's first byte to make the header fail decoding.
buf[0] = 255;
- assert_eq!(pipe.server.recv(&mut buf[..written]), Ok(written));
+ assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
}
#[test]
@@ -7825,7 +7942,7 @@ mod tests {
let mut pipe = testing::Pipe::default().unwrap();
assert_eq!(pipe.handshake(), Ok(()));
- assert_eq!(pipe.server.recv(&mut buf[..0]), Err(Error::BufferTooShort));
+ assert_eq!(pipe.server_recv(&mut buf[..0]), Err(Error::BufferTooShort));
}
#[test]
@@ -8169,7 +8286,7 @@ mod tests {
let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
// Client sends initial flight.
- let mut len = pipe.client.send(&mut buf).unwrap();
+ let (mut len, _) = pipe.client.send(&mut buf).unwrap();
// Server sends Retry packet.
let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap();
@@ -8193,16 +8310,17 @@ mod tests {
.unwrap();
// Client receives Retry and sends new Initial.
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
- len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap();
assert_eq!(&hdr.token.unwrap(), token);
// Server accepts connection.
- pipe.server = accept(&scid, Some(&odcid), &mut config).unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ let from = "127.0.0.1:1234".parse().unwrap();
+ pipe.server = accept(&scid, Some(&odcid), from, &mut config).unwrap();
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
assert_eq!(pipe.advance(), Ok(()));
@@ -8228,7 +8346,7 @@ mod tests {
let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
// Client sends initial flight.
- let mut len = pipe.client.send(&mut buf).unwrap();
+ let (mut len, _) = pipe.client.send(&mut buf).unwrap();
// Server sends Retry packet.
let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap();
@@ -8250,14 +8368,15 @@ mod tests {
.unwrap();
// Client receives Retry and sends new Initial.
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
- len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
// Server accepts connection and send first flight. But original
// destination connection ID is ignored.
- pipe.server = accept(&scid, None, &mut config).unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ let from = "127.0.0.1:1234".parse().unwrap();
+ pipe.server = accept(&scid, None, from, &mut config).unwrap();
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
let flight = testing::emit_flight(&mut pipe.server).unwrap();
@@ -8285,7 +8404,7 @@ mod tests {
let mut pipe = testing::Pipe::with_server_config(&mut config).unwrap();
// Client sends initial flight.
- let mut len = pipe.client.send(&mut buf).unwrap();
+ let (mut len, _) = pipe.client.send(&mut buf).unwrap();
// Server sends Retry packet.
let hdr = Header::from_slice(&mut buf[..len], MAX_CONN_ID_LEN).unwrap();
@@ -8307,15 +8426,16 @@ mod tests {
.unwrap();
// Client receives Retry and sends new Initial.
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
- len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
// Server accepts connection and send first flight. But original
// destination connection ID is invalid.
+ let from = "127.0.0.1:1234".parse().unwrap();
let odcid = ConnectionId::from_ref(b"bogus value");
- pipe.server = accept(&scid, Some(&odcid), &mut config).unwrap();
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ pipe.server = accept(&scid, Some(&odcid), from, &mut config).unwrap();
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
let flight = testing::emit_flight(&mut pipe.server).unwrap();
@@ -8371,7 +8491,7 @@ mod tests {
assert_eq!(pipe.client.stream_send(8, b"aaaaaaaaaaa", false), Ok(10));
assert_eq!(pipe.client.blocked_limit, Some(30));
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(pipe.client.blocked_limit, None);
let frames =
@@ -8408,7 +8528,7 @@ mod tests {
assert_eq!(pipe.client.stream_send(0, b"aaaaaa", false), Ok(5));
assert_eq!(pipe.client.streams.blocked().len(), 1);
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(pipe.client.streams.blocked().len(), 0);
let frames =
@@ -8441,7 +8561,7 @@ mod tests {
// again.
assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1));
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(pipe.client.streams.blocked().len(), 0);
let frames =
@@ -8464,7 +8584,7 @@ mod tests {
assert_eq!(pipe.client.stream_send(0, b"aaaaaa", false), Ok(0));
assert_eq!(pipe.client.streams.blocked().len(), 1);
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(pipe.client.streams.blocked().len(), 0);
let frames =
@@ -8767,7 +8887,8 @@ mod tests {
let mut off = 0;
for _ in 1..=3 {
- let len = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
+ let (len, _) =
+ pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8789,7 +8910,8 @@ mod tests {
let mut off = 0;
for _ in 1..=3 {
- let len = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
+ let (len, _) =
+ pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8811,7 +8933,8 @@ mod tests {
let mut off = 0;
for _ in 1..=3 {
- let len = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
+ let (len, _) =
+ pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8833,7 +8956,8 @@ mod tests {
let mut off = 0;
for _ in 1..=3 {
- let len = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
+ let (len, _) =
+ pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8846,7 +8970,8 @@ mod tests {
})
);
- let len = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
+ let (len, _) =
+ pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8869,7 +8994,8 @@ mod tests {
let mut off = 0;
for _ in 1..=3 {
- let len = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
+ let (len, _) =
+ pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8953,7 +9079,7 @@ mod tests {
assert_eq!(pipe.server.stream_priority(0, 20, true), Ok(()));
// First is stream 8.
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8967,7 +9093,7 @@ mod tests {
);
// Then is stream 0.
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8981,7 +9107,7 @@ mod tests {
);
// Then are stream 12 and 4, with the same priority.
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -8994,7 +9120,7 @@ mod tests {
})
);
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.client, &mut buf, len).unwrap();
@@ -9036,7 +9162,7 @@ mod tests {
assert_eq!(pipe.client.recovery.loss_probes[epoch], 1);
// Client retransmits stream data in PTO probe.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(pipe.client.recovery.loss_probes[epoch], 0);
let frames =
@@ -9064,7 +9190,8 @@ mod tests {
let mut pipe = testing::Pipe::default().unwrap();
// Client sends Initial packet.
- assert_eq!(pipe.client.send(&mut buf), Ok(1200));
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
+ assert_eq!(len, 1200);
// Wait for PTO to expire.
let timer = pipe.client.timeout().unwrap();
@@ -9076,7 +9203,8 @@ mod tests {
assert_eq!(pipe.client.recovery.loss_probes[epoch], 1);
// Client sends PTO probe.
- assert_eq!(pipe.client.send(&mut buf), Ok(1200));
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
+ assert_eq!(len, 1200);
assert_eq!(pipe.client.recovery.loss_probes[epoch], 0);
// Wait for PTO to expire.
@@ -9088,11 +9216,13 @@ mod tests {
assert_eq!(pipe.client.recovery.loss_probes[epoch], 2);
// Client sends first PTO probe.
- assert_eq!(pipe.client.send(&mut buf), Ok(1200));
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
+ assert_eq!(len, 1200);
assert_eq!(pipe.client.recovery.loss_probes[epoch], 1);
// Client sends second PTO probe.
- assert_eq!(pipe.client.send(&mut buf), Ok(1200));
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
+ assert_eq!(len, 1200);
assert_eq!(pipe.client.recovery.loss_probes[epoch], 0);
}
@@ -9103,26 +9233,26 @@ mod tests {
let mut pipe = testing::Pipe::default().unwrap();
// Client sends first flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(len, MIN_CLIENT_INITIAL_LEN);
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
// Server sends first flight.
- let len = pipe.server.send(&mut buf).unwrap();
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
assert_eq!(len, MIN_CLIENT_INITIAL_LEN);
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
- let len = pipe.server.send(&mut buf).unwrap();
- assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
+ let (len, _) = pipe.server.send(&mut buf).unwrap();
+ assert_eq!(pipe.client_recv(&mut buf[..len]), Ok(len));
// Client sends stream data.
assert_eq!(pipe.client.is_established(), true);
assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5));
// Client sends second flight.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(len, MIN_CLIENT_INITIAL_LEN);
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
// None of the sent packets should have been dropped.
assert_eq!(pipe.client.sent_count, pipe.server.recv_count);
@@ -9153,12 +9283,12 @@ mod tests {
assert_eq!(pipe.server.handshake_status().peer_verified_address, true);
// Client sends padded Initial.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(len, 1200);
// Server receives client's Initial and sends own Initial and Handshake
// until it's blocked by the anti-amplification limit.
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
let flight = testing::emit_flight(&mut pipe.server).unwrap();
assert_eq!(pipe.client.handshake_status().has_handshake_keys, false);
@@ -9189,11 +9319,11 @@ mod tests {
let mut pipe = testing::Pipe::default().unwrap();
// Client sends padded Initial.
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_eq!(len, 1200);
// Server receives client's Initial and sends own Initial and Handshake.
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
let flight = testing::emit_flight(&mut pipe.server).unwrap();
testing::process_flight(&mut pipe.client, flight).unwrap();
@@ -9202,7 +9332,7 @@ mod tests {
let (ty, len) = pipe.client.send_single(&mut buf, false).unwrap();
assert_eq!(ty, Type::Initial);
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
// Client sends Handshake packet.
let (ty, len) = pipe.client.send_single(&mut buf, false).unwrap();
@@ -9215,7 +9345,7 @@ mod tests {
assert_eq!(hdr.ty, Type::Initial);
// Server receives corrupted packet without returning an error.
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
}
#[test]
@@ -9264,13 +9394,13 @@ mod tests {
assert!(!pipe.client.recovery.app_limited());
assert_eq!(pipe.client.dgram_send_queue.byte_size(), 1_000_000);
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
assert_ne!(pipe.client.dgram_send_queue.byte_size(), 0);
assert_ne!(pipe.client.dgram_send_queue.byte_size(), 1_000_000);
assert!(!pipe.client.recovery.app_limited());
- assert_eq!(pipe.server.recv(&mut buf[..len]), Ok(len));
+ assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len));
let flight = testing::emit_flight(&mut pipe.client).unwrap();
testing::process_flight(&mut pipe.server, flight).unwrap();
@@ -9612,7 +9742,7 @@ mod tests {
Err(Error::Done)
);
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
@@ -9638,7 +9768,7 @@ mod tests {
assert_eq!(pipe.client.close(true, 0x4321, b"hello!"), Err(Error::Done));
- let len = pipe.client.send(&mut buf).unwrap();
+ let (len, _) = pipe.client.send(&mut buf).unwrap();
let frames =
testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
@@ -9693,10 +9823,12 @@ mod tests {
let mut client_scid = [0; 16];
rand::rand_bytes(&mut client_scid[..]);
let client_scid = ConnectionId::from_ref(&client_scid);
+ let client_addr = "127.0.0.1:1234".parse().unwrap();
let mut server_scid = [0; 16];
rand::rand_bytes(&mut server_scid[..]);
let server_scid = ConnectionId::from_ref(&server_scid);
+ let server_addr = "127.0.0.1:4321".parse().unwrap();
let mut client_config = Config::new(crate::PROTOCOL_VERSION).unwrap();
client_config
@@ -9722,9 +9854,15 @@ mod tests {
server_config.set_max_send_udp_payload_size(1500);
let mut pipe = testing::Pipe {
- client: connect(Some("quic.tech"), &client_scid, &mut client_config)
+ client: connect(
+ Some("quic.tech"),
+ &client_scid,
+ client_addr,
+ &mut client_config,
+ )
+ .unwrap(),
+ server: accept(&server_scid, None, server_addr, &mut server_config)
.unwrap(),
- server: accept(&server_scid, None, &mut server_config).unwrap(),
};
// Before handshake
diff --git a/tools/apps/src/bin/quiche-server.rs b/tools/apps/src/bin/quiche-server.rs
index 303f5d68..03b77c2d 100644
--- a/tools/apps/src/bin/quiche-server.rs
+++ b/tools/apps/src/bin/quiche-server.rs
@@ -141,8 +141,7 @@ fn main() {
// Find the shorter timeout from all the active connections.
//
// TODO: use event loop that properly supports timers
- let timeout =
- clients.values().filter_map(|(_, c)| c.conn.timeout()).min();
+ let timeout = clients.values().filter_map(|c| c.conn.timeout()).min();
poll.poll(&mut events, timeout).unwrap();
@@ -155,12 +154,12 @@ fn main() {
if events.is_empty() {
trace!("timed out");
- clients.values_mut().for_each(|(_, c)| c.conn.on_timeout());
+ clients.values_mut().for_each(|c| c.conn.on_timeout());
break 'read;
}
- let (len, src) = match socket.recv_from(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -211,7 +210,7 @@ fn main() {
// Lookup a connection based on the packet's connection ID. If there
// is no connection matching, create a new one.
- let (_, client) = if !clients.contains_key(&hdr.dcid) &&
+ let client = if !clients.contains_key(&hdr.dcid) &&
!clients.contains_key(&conn_id)
{
if hdr.ty != quiche::Type::Initial {
@@ -228,7 +227,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &src) {
+ if let Err(e) = socket.send_to(out, &from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
trace!("send() would block");
break;
@@ -253,7 +252,7 @@ fn main() {
warn!("Doing stateless retry");
let scid = quiche::ConnectionId::from_ref(&scid);
- let new_token = mint_token(&hdr, &src);
+ let new_token = mint_token(&hdr, &from);
let len = quiche::retry(
&hdr.scid,
@@ -267,7 +266,7 @@ fn main() {
let out = &out[..len];
- if let Err(e) = socket.send_to(out, &src) {
+ if let Err(e) = socket.send_to(out, &from) {
if e.kind() == std::io::ErrorKind::WouldBlock {
trace!("send() would block");
break;
@@ -278,7 +277,7 @@ fn main() {
continue 'read;
}
- odcid = validate_token(&src, token);
+ odcid = validate_token(&from, token);
// The token was not valid, meaning the retry failed, so
// drop the packet.
@@ -303,7 +302,8 @@ fn main() {
#[allow(unused_mut)]
let mut conn =
- quiche::accept(&scid, odcid.as_ref(), &mut config).unwrap();
+ quiche::accept(&scid, odcid.as_ref(), from, &mut config)
+ .unwrap();
if let Some(keylog) = &mut keylog {
if let Ok(keylog) = keylog.try_clone() {
@@ -335,7 +335,7 @@ fn main() {
app_proto_selected: false,
};
- clients.insert(scid.clone(), (src, client));
+ clients.insert(scid.clone(), client);
clients.get_mut(&scid).unwrap()
} else {
@@ -346,8 +346,10 @@ fn main() {
}
};
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match client.conn.recv(pkt_buf) {
+ let read = match client.conn.recv(pkt_buf, recv_info) {
Ok(v) => v,
Err(e) => {
@@ -445,9 +447,9 @@ fn main() {
// Generate outgoing QUIC packets for all active connections and send
// them on the UDP socket, until quiche reports that there are no more
// packets to be sent.
- for (peer, client) in clients.values_mut() {
+ for client in clients.values_mut() {
loop {
- let write = match client.conn.send(&mut out) {
+ let (write, send_info) = match client.conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -464,7 +466,7 @@ fn main() {
};
// TODO: coalesce packets.
- if let Err(e) = socket.send_to(&out[..write], &peer) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
trace!("send() would block");
break;
@@ -478,7 +480,7 @@ fn main() {
}
// Garbage collect closed connections.
- clients.retain(|_, (_, ref mut c)| {
+ clients.retain(|_, ref mut c| {
trace!("Collecting garbage");
if c.conn.is_closed() {
diff --git a/tools/apps/src/client.rs b/tools/apps/src/client.rs
index 0c9303fe..24c8121f 100644
--- a/tools/apps/src/client.rs
+++ b/tools/apps/src/client.rs
@@ -157,7 +157,8 @@ pub fn connect(
// Create a QUIC connection and initiate handshake.
let mut conn =
- quiche::connect(connect_url.domain(), &scid, &mut config).unwrap();
+ quiche::connect(connect_url.domain(), &scid, peer_addr, &mut config)
+ .unwrap();
if let Some(keylog) = &mut keylog {
if let Ok(keylog) = keylog.try_clone() {
@@ -193,9 +194,9 @@ pub fn connect(
scid,
);
- let write = conn.send(&mut out).expect("initial send failed");
+ let (write, send_info) = conn.send(&mut out).expect("initial send failed");
- while let Err(e) = socket.send(&out[..write]) {
+ while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
trace!("send() would block");
continue;
@@ -229,7 +230,7 @@ pub fn connect(
break 'read;
}
- let len = match socket.recv(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -260,8 +261,10 @@ pub fn connect(
pkt_count += 1;
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match conn.recv(&mut buf[..len]) {
+ let read = match conn.recv(&mut buf[..len], recv_info) {
Ok(v) => v,
Err(e) => {
@@ -381,7 +384,7 @@ pub fn connect(
// Generate outgoing QUIC packets and send them on the UDP socket, until
// quiche reports that there are no more packets to be sent.
loop {
- let write = match conn.send(&mut out) {
+ let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -397,7 +400,7 @@ pub fn connect(
},
};
- if let Err(e) = socket.send(&out[..write]) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
trace!("send() would block");
break;
diff --git a/tools/apps/src/common.rs b/tools/apps/src/common.rs
index 49e75f48..fa1d7d80 100644
--- a/tools/apps/src/common.rs
+++ b/tools/apps/src/common.rs
@@ -39,7 +39,6 @@ use std::rc::Rc;
use std::cell::RefCell;
-use std::net;
use std::path;
use quiche::ConnectionId;
@@ -97,7 +96,7 @@ pub struct Client {
pub partial_responses: std::collections::HashMap<u64, PartialResponse>,
}
-pub type ClientMap = HashMap<ConnectionId<'static>, (net::SocketAddr, Client)>;
+pub type ClientMap = HashMap<ConnectionId<'static>, Client>;
/// Makes a buffered writer for a resource with a target URL.
///
diff --git a/tools/http3_test/src/runner.rs b/tools/http3_test/src/runner.rs
index a789286d..43607033 100644
--- a/tools/http3_test/src/runner.rs
+++ b/tools/http3_test/src/runner.rs
@@ -123,7 +123,8 @@ pub fn run(
// Create a QUIC connection and initiate handshake.
let url = &test.endpoint();
- let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
+ let mut conn =
+ quiche::connect(url.domain(), &scid, peer_addr, &mut config).unwrap();
if let Some(session_file) = &session_file {
if let Ok(session) = std::fs::read(session_file) {
@@ -131,9 +132,9 @@ pub fn run(
}
}
- let write = conn.send(&mut out).expect("initial send failed");
+ let (write, send_info) = conn.send(&mut out).expect("initial send failed");
- while let Err(e) = socket.send(&out[..write]) {
+ while let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
continue;
@@ -165,7 +166,7 @@ pub fn run(
break 'read;
}
- let len = match socket.recv(&mut buf) {
+ let (len, from) = match socket.recv_from(&mut buf) {
Ok(v) => v,
Err(e) => {
@@ -185,8 +186,10 @@ pub fn run(
debug!("got {} bytes", len);
+ let recv_info = quiche::RecvInfo { from };
+
// Process potentially coalesced packets.
- let read = match conn.recv(&mut buf[..len]) {
+ let read = match conn.recv(&mut buf[..len], recv_info) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -347,7 +350,7 @@ pub fn run(
// Generate outgoing QUIC packets and send them on the UDP socket, until
// quiche reports that there are no more packets to be sent.
loop {
- let write = match conn.send(&mut out) {
+ let (write, send_info) = match conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
@@ -362,7 +365,7 @@ pub fn run(
},
};
- if let Err(e) = socket.send(&out[..write]) {
+ if let Err(e) = socket.send_to(&out[..write], &send_info.to) {
if e.kind() == std::io::ErrorKind::WouldBlock {
debug!("send() would block");
break;