aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-06-08 17:53:00 -0700
committerJoel Galenson <jgalenson@google.com>2021-06-21 11:43:07 -0700
commit96d408b0bb385e0d68122111acd9c9f3aefea6c1 (patch)
treef322aa3a0b30f78d0f83e74509d4af2e92f0f9e0 /examples
parentae2637dc45ccca8782c260803c0547a6b6d1641c (diff)
downloadquiche-96d408b0bb385e0d68122111acd9c9f3aefea6c1.tar.gz
Upgrade rust/crates/quiche to 0.9.0android-mainline-12.0.0_r99android-mainline-12.0.0_r96android-mainline-12.0.0_r95android-mainline-12.0.0_r94android-mainline-12.0.0_r93android-mainline-12.0.0_r84android-mainline-12.0.0_r83android-mainline-12.0.0_r82android-mainline-12.0.0_r81android-mainline-12.0.0_r80android-mainline-12.0.0_r8android-mainline-12.0.0_r79android-mainline-12.0.0_r77android-mainline-12.0.0_r70android-mainline-12.0.0_r67android-mainline-12.0.0_r66android-mainline-12.0.0_r65android-mainline-12.0.0_r64android-mainline-12.0.0_r63android-mainline-12.0.0_r6android-mainline-12.0.0_r59android-mainline-12.0.0_r58android-mainline-12.0.0_r57android-mainline-12.0.0_r53android-mainline-12.0.0_r52android-mainline-12.0.0_r51android-mainline-12.0.0_r49android-mainline-12.0.0_r40android-mainline-12.0.0_r38android-mainline-12.0.0_r37android-mainline-12.0.0_r35android-mainline-12.0.0_r34android-mainline-12.0.0_r32android-mainline-12.0.0_r25android-mainline-12.0.0_r23android-mainline-12.0.0_r20android-mainline-12.0.0_r18android-mainline-12.0.0_r17android-mainline-12.0.0_r16android-mainline-12.0.0_r15android-mainline-12.0.0_r14android-mainline-12.0.0_r126android-mainline-12.0.0_r125android-mainline-12.0.0_r124android-mainline-12.0.0_r123android-mainline-12.0.0_r122android-mainline-12.0.0_r114android-mainline-12.0.0_r110android-mainline-12.0.0_r109android-mainline-12.0.0_r108android-mainline-12.0.0_r107android-mainline-12.0.0_r100aml_wif_311811030aml_tet_311811050aml_sdk_311710000aml_pco_311011000android12-mainline-wifi-releaseandroid12-mainline-tethering-releaseandroid12-mainline-statsd-releaseandroid12-mainline-sdkext-releaseandroid12-mainline-resolv-releaseandroid12-mainline-permission-releaseandroid12-mainline-networkstack-releaseandroid12-mainline-conscrypt-releaseandroid12-mainline-captiveportallogin-release
Test: make Change-Id: I438d6a167e6e0bbfe38785ba13c33a285d1c510b
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile4
-rw-r--r--examples/client.c41
-rw-r--r--examples/client.rs27
-rw-r--r--examples/http3-client.c57
-rw-r--r--examples/http3-client.rs38
-rw-r--r--examples/http3-server.c36
-rw-r--r--examples/http3-server.rs106
-rw-r--r--examples/qpack-decode.rs4
-rw-r--r--examples/qpack-encode.rs2
-rw-r--r--examples/server.c53
-rw-r--r--examples/server.rs82
11 files changed, 271 insertions, 179 deletions
diff --git a/examples/Makefile b/examples/Makefile
index bb75e7d..5660bbd 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -34,7 +34,7 @@ http3-server: http3-server.c $(INCLUDE_DIR)/quiche.h $(LIB_DIR)/libquiche.a
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(INCS) $(LIBS)
$(LIB_DIR)/libquiche.a: $(shell find $(SOURCE_DIR) -type f -name '*.rs')
- cd .. && cargo build --target-dir $(BUILD_DIR)
+ cd .. && cargo build --target-dir $(BUILD_DIR) --features ffi
clean:
- @$(RM) -rf client server http3-client http3-server build/
+ @$(RM) -rf client server http3-client http3-server build/ *.dSYM/
diff --git a/examples/client.c b/examples/client.c
index bca9781..0df9665 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");
@@ -228,11 +246,6 @@ int main(int argc, char *argv[]) {
return -1;
}
- if (connect(sock, peer->ai_addr, peer->ai_addrlen) < 0) {
- perror("failed to connect socket");
- return -1;
- }
-
quiche_config *config = quiche_config_new(0xbabababa);
if (config == NULL) {
fprintf(stderr, "failed to create config\n");
@@ -240,10 +253,11 @@ int main(int argc, char *argv[]) {
}
quiche_config_set_application_protos(config,
- (uint8_t *) "\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 27);
+ (uint8_t *) "\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 38);
quiche_config_set_max_idle_timeout(config, 5000);
- quiche_config_set_max_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE);
quiche_config_set_initial_max_data(config, 10000000);
quiche_config_set_initial_max_stream_data_bidi_local(config, 1000000);
quiche_config_set_initial_max_stream_data_uni(config, 1000000);
@@ -268,8 +282,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 2e427f6..88490aa 100644
--- a/examples/client.rs
+++ b/examples/client.rs
@@ -69,7 +69,6 @@ fn main() {
// Create the UDP socket backing the QUIC connection, and register it with
// the event loop.
let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
- socket.connect(peer_addr).unwrap();
let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
poll.register(
@@ -87,11 +86,14 @@ fn main() {
config.verify_peer(false);
config
- .set_application_protos(b"\x05hq-29\x05hq-28\x05hq-27\x08http/0.9")
+ .set_application_protos(
+ b"\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9",
+ )
.unwrap();
config.set_max_idle_timeout(5000);
- config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE as u64);
+ config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
+ config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_initial_max_data(10_000_000);
config.set_initial_max_stream_data_bidi_local(1_000_000);
config.set_initial_max_stream_data_bidi_remote(1_000_000);
@@ -103,8 +105,11 @@ fn main() {
let mut scid = [0; quiche::MAX_CONN_ID_LEN];
SystemRandom::new().fill(&mut scid[..]).unwrap();
+ 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 {}",
@@ -113,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;
@@ -146,7 +151,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) => {
@@ -163,8 +168,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) => {
@@ -228,7 +235,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) => {
@@ -244,7 +251,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 8c75309..6b263ff 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);
@@ -239,14 +257,18 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
}
case QUICHE_H3_EVENT_DATA: {
- ssize_t len = quiche_h3_recv_body(conn_io->http3,
- conn_io->conn, s,
- buf, sizeof(buf));
- if (len <= 0) {
- break;
+ for (;;) {
+ ssize_t len = quiche_h3_recv_body(conn_io->http3,
+ conn_io->conn, s,
+ buf, sizeof(buf));
+
+ if (len <= 0) {
+ break;
+ }
+
+ printf("%.*s", (int) len, buf);
}
- printf("%.*s", (int) len, buf);
break;
}
@@ -258,7 +280,7 @@ static void recv_cb(EV_P_ ev_io *w, int revents) {
case QUICHE_H3_EVENT_DATAGRAM:
break;
-
+
case QUICHE_H3_EVENT_GOAWAY: {
fprintf(stderr, "got GOAWAY\n");
break;
@@ -322,11 +344,6 @@ int main(int argc, char *argv[]) {
return -1;
}
- if (connect(sock, peer->ai_addr, peer->ai_addrlen) < 0) {
- perror("failed to connect socket");
- return -1;
- }
-
quiche_config *config = quiche_config_new(0xbabababa);
if (config == NULL) {
fprintf(stderr, "failed to create config\n");
@@ -338,7 +355,8 @@ int main(int argc, char *argv[]) {
sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1);
quiche_config_set_max_idle_timeout(config, 5000);
- quiche_config_set_max_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE);
quiche_config_set_initial_max_data(config, 10000000);
quiche_config_set_initial_max_stream_data_bidi_local(config, 1000000);
quiche_config_set_initial_max_stream_data_bidi_remote(config, 1000000);
@@ -366,8 +384,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 a93d67e..2acb2ca 100644
--- a/examples/http3-client.rs
+++ b/examples/http3-client.rs
@@ -67,7 +67,6 @@ fn main() {
// Create the UDP socket backing the QUIC connection, and register it with
// the event loop.
let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
- socket.connect(peer_addr).unwrap();
let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
poll.register(
@@ -89,7 +88,8 @@ fn main() {
.unwrap();
config.set_max_idle_timeout(5000);
- config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE as u64);
+ config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
+ config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_initial_max_data(10_000_000);
config.set_initial_max_stream_data_bidi_local(1_000_000);
config.set_initial_max_stream_data_bidi_remote(1_000_000);
@@ -104,8 +104,11 @@ fn main() {
let mut scid = [0; quiche::MAX_CONN_ID_LEN];
SystemRandom::new().fill(&mut scid[..]).unwrap();
+ 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 {}",
@@ -114,9 +117,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;
@@ -138,11 +141,14 @@ fn main() {
}
let req = vec![
- quiche::h3::Header::new(":method", "GET"),
- quiche::h3::Header::new(":scheme", url.scheme()),
- quiche::h3::Header::new(":authority", url.host_str().unwrap()),
- quiche::h3::Header::new(":path", &path),
- quiche::h3::Header::new("user-agent", "quiche"),
+ quiche::h3::Header::new(b":method", b"GET"),
+ quiche::h3::Header::new(b":scheme", url.scheme().as_bytes()),
+ quiche::h3::Header::new(
+ b":authority",
+ url.host_str().unwrap().as_bytes(),
+ ),
+ quiche::h3::Header::new(b":path", path.as_bytes()),
+ quiche::h3::Header::new(b"user-agent", b"quiche"),
];
let req_start = std::time::Instant::now();
@@ -166,7 +172,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) => {
@@ -183,8 +189,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) => {
@@ -235,7 +243,7 @@ fn main() {
},
Ok((stream_id, quiche::h3::Event::Data)) => {
- if let Ok(read) =
+ while let Ok(read) =
http3_conn.recv_body(&mut conn, stream_id, &mut buf)
{
debug!(
@@ -280,7 +288,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) => {
@@ -296,7 +304,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 b6b3041..73c29ae 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);
@@ -532,7 +549,8 @@ int main(int argc, char *argv[]) {
sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1);
quiche_config_set_max_idle_timeout(config, 5000);
- quiche_config_set_max_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE);
quiche_config_set_initial_max_data(config, 10000000);
quiche_config_set_initial_max_stream_data_bidi_local(config, 1000000);
quiche_config_set_initial_max_stream_data_bidi_remote(config, 1000000);
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index 4c41cbb..e84d1ea 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -53,7 +53,7 @@ struct Client {
partial_responses: HashMap<u64, PartialResponse>,
}
-type ClientMap = HashMap<Vec<u8>, (net::SocketAddr, Client)>;
+type ClientMap = HashMap<quiche::ConnectionId<'static>, Client>;
fn main() {
let mut buf = [0; 65535];
@@ -100,7 +100,8 @@ fn main() {
.unwrap();
config.set_max_idle_timeout(5000);
- config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE as u64);
+ config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
+ config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_initial_max_data(10_000_000);
config.set_initial_max_stream_data_bidi_local(1_000_000);
config.set_initial_max_stream_data_bidi_remote(1_000_000);
@@ -122,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();
@@ -136,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) => {
@@ -177,11 +177,12 @@ fn main() {
let conn_id = ring::hmac::sign(&conn_id_seed, &hdr.dcid);
let conn_id = &conn_id.as_ref()[..quiche::MAX_CONN_ID_LEN];
+ let conn_id = conn_id.to_vec().into();
// 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) &&
- !clients.contains_key(conn_id)
+ let client = if !clients.contains_key(&hdr.dcid) &&
+ !clients.contains_key(&conn_id)
{
if hdr.ty != quiche::Type::Initial {
error!("Packet is not Initial");
@@ -197,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;
@@ -211,6 +212,8 @@ fn main() {
let mut scid = [0; quiche::MAX_CONN_ID_LEN];
scid.copy_from_slice(&conn_id);
+ let scid = quiche::ConnectionId::from_ref(&scid);
+
// Token is always present in Initial packets.
let token = hdr.token.as_ref().unwrap();
@@ -218,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,
@@ -232,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;
@@ -243,11 +246,11 @@ 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.
- if odcid == None {
+ if odcid.is_none() {
error!("Invalid address validation token");
continue 'read;
}
@@ -257,17 +260,15 @@ fn main() {
continue 'read;
}
- // Reuse the source connection ID we sent in the Retry
- // packet, instead of changing it again.
- scid.copy_from_slice(&hdr.dcid);
+ // Reuse the source connection ID we sent in the Retry packet,
+ // instead of changing it again.
+ let scid = hdr.dcid.clone();
- debug!(
- "New connection: dcid={} scid={}",
- hex_dump(&hdr.dcid),
- hex_dump(&scid)
- );
+ debug!("New connection: dcid={:?} scid={:?}", hdr.dcid, scid);
- let conn = quiche::accept(&scid, odcid, &mut config).unwrap();
+ let conn =
+ quiche::accept(&scid, odcid.as_ref(), from, &mut config)
+ .unwrap();
let client = Client {
conn,
@@ -275,19 +276,21 @@ fn main() {
partial_responses: HashMap::new(),
};
- clients.insert(scid.to_vec(), (src, client));
+ clients.insert(scid.clone(), client);
- clients.get_mut(&scid[..]).unwrap()
+ clients.get_mut(&scid).unwrap()
} else {
match clients.get_mut(&hdr.dcid) {
Some(v) => v,
- None => clients.get_mut(conn_id).unwrap(),
+ None => clients.get_mut(&conn_id).unwrap(),
}
};
+ 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) => {
@@ -382,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) => {
@@ -400,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;
@@ -415,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() {
@@ -464,7 +466,7 @@ fn mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8> {
/// authenticate of the token. *It should not be used in production system*.
fn validate_token<'a>(
src: &net::SocketAddr, token: &'a [u8],
-) -> Option<&'a [u8]> {
+) -> Option<quiche::ConnectionId<'a>> {
if token.len() < 6 {
return None;
}
@@ -484,9 +486,7 @@ fn validate_token<'a>(
return None;
}
- let token = &token[addr.len()..];
-
- Some(&token[..])
+ Some(quiche::ConnectionId::from_ref(&token[addr.len()..]))
}
/// Handles incoming HTTP/3 requests.
@@ -535,6 +535,8 @@ fn handle_request(
let written = match http3_conn.send_body(conn, stream_id, &body, true) {
Ok(v) => v,
+ Err(quiche::h3::Error::Done) => 0,
+
Err(e) => {
error!("{} stream send failed {:?}", conn.trace_id(), e);
return;
@@ -558,25 +560,24 @@ fn build_response(
) -> (Vec<quiche::h3::Header>, Vec<u8>) {
let mut file_path = std::path::PathBuf::from(root);
let mut path = std::path::Path::new("");
- let mut method = "";
+ let mut method = None;
// Look for the request's path and method.
for hdr in request {
match hdr.name() {
- ":path" => {
- path = std::path::Path::new(hdr.value());
- },
+ b":path" =>
+ path = std::path::Path::new(
+ std::str::from_utf8(hdr.value()).unwrap(),
+ ),
- ":method" => {
- method = hdr.value();
- },
+ b":method" => method = Some(hdr.value()),
_ => (),
}
}
let (status, body) = match method {
- "GET" => {
+ Some(b"GET") => {
for c in path.components() {
if let std::path::Component::Normal(v) = c {
file_path.push(v)
@@ -594,9 +595,12 @@ fn build_response(
};
let headers = vec![
- quiche::h3::Header::new(":status", &status.to_string()),
- quiche::h3::Header::new("server", "quiche"),
- quiche::h3::Header::new("content-length", &body.len().to_string()),
+ quiche::h3::Header::new(b":status", status.to_string().as_bytes()),
+ quiche::h3::Header::new(b"server", b"quiche"),
+ quiche::h3::Header::new(
+ b"content-length",
+ body.len().to_string().as_bytes(),
+ ),
];
(headers, body)
@@ -637,7 +641,11 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
let written = match http3_conn.send_body(conn, stream_id, body, true) {
Ok(v) => v,
+ Err(quiche::h3::Error::Done) => 0,
+
Err(e) => {
+ client.partial_responses.remove(&stream_id);
+
error!("{} stream send failed {:?}", conn.trace_id(), e);
return;
},
@@ -649,9 +657,3 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
client.partial_responses.remove(&stream_id);
}
}
-
-fn hex_dump(buf: &[u8]) -> String {
- let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
-
- vec.join("")
-}
diff --git a/examples/qpack-decode.rs b/examples/qpack-decode.rs
index 8468a85..d2aaaa5 100644
--- a/examples/qpack-decode.rs
+++ b/examples/qpack-decode.rs
@@ -77,7 +77,9 @@ fn main() {
}
for hdr in dec.decode(&data[..len], std::u64::MAX).unwrap() {
- println!("{}\t{}", hdr.name(), hdr.value());
+ let name = std::str::from_utf8(hdr.name()).unwrap();
+ let value = std::str::from_utf8(hdr.value()).unwrap();
+ println!("{}\t{}", name, value);
}
println!();
diff --git a/examples/qpack-encode.rs b/examples/qpack-encode.rs
index e381227..5215fe4 100644
--- a/examples/qpack-encode.rs
+++ b/examples/qpack-encode.rs
@@ -83,6 +83,6 @@ fn main() {
let name = line.split('\t').next().unwrap();
let value = line.split('\t').last().unwrap();
- headers.push(h3::Header::new(name, value));
+ headers.push(h3::Header::new(name.as_bytes(), value.as_bytes()));
}
}
diff --git a/examples/server.c b/examples/server.c
index 025e1d5..a97250f 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);
@@ -451,10 +473,11 @@ int main(int argc, char *argv[]) {
quiche_config_load_priv_key_from_pem_file(config, "./cert.key");
quiche_config_set_application_protos(config,
- (uint8_t *) "\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 27);
+ (uint8_t *) "\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 38);
quiche_config_set_max_idle_timeout(config, 5000);
- quiche_config_set_max_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE);
+ quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE);
quiche_config_set_initial_max_data(config, 10000000);
quiche_config_set_initial_max_stream_data_bidi_local(config, 1000000);
quiche_config_set_initial_max_stream_data_bidi_remote(config, 1000000);
diff --git a/examples/server.rs b/examples/server.rs
index 8213d95..90f0102 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -47,7 +47,7 @@ struct Client {
partial_responses: HashMap<u64, PartialResponse>,
}
-type ClientMap = HashMap<Vec<u8>, (net::SocketAddr, Client)>;
+type ClientMap = HashMap<quiche::ConnectionId<'static>, Client>;
fn main() {
let mut buf = [0; 65535];
@@ -90,11 +90,14 @@ fn main() {
.unwrap();
config
- .set_application_protos(b"\x05hq-29\x05hq-28\x05hq-27\x08http/0.9")
+ .set_application_protos(
+ b"\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9",
+ )
.unwrap();
config.set_max_idle_timeout(5000);
- config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE as u64);
+ config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
+ config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_initial_max_data(10_000_000);
config.set_initial_max_stream_data_bidi_local(1_000_000);
config.set_initial_max_stream_data_bidi_remote(1_000_000);
@@ -114,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();
@@ -128,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) => {
@@ -169,11 +171,12 @@ fn main() {
let conn_id = ring::hmac::sign(&conn_id_seed, &hdr.dcid);
let conn_id = &conn_id.as_ref()[..quiche::MAX_CONN_ID_LEN];
+ let conn_id = conn_id.to_vec().into();
// 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) &&
- !clients.contains_key(conn_id)
+ let client = if !clients.contains_key(&hdr.dcid) &&
+ !clients.contains_key(&conn_id)
{
if hdr.ty != quiche::Type::Initial {
error!("Packet is not Initial");
@@ -189,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;
@@ -203,6 +206,8 @@ fn main() {
let mut scid = [0; quiche::MAX_CONN_ID_LEN];
scid.copy_from_slice(&conn_id);
+ let scid = quiche::ConnectionId::from_ref(&scid);
+
// Token is always present in Initial packets.
let token = hdr.token.as_ref().unwrap();
@@ -210,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,
@@ -224,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;
@@ -235,11 +240,11 @@ 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.
- if odcid == None {
+ if odcid.is_none() {
error!("Invalid address validation token");
continue 'read;
}
@@ -249,36 +254,36 @@ fn main() {
continue 'read;
}
- // Reuse the source connection ID we sent in the Retry
- // packet, instead of changing it again.
- scid.copy_from_slice(&hdr.dcid);
+ // Reuse the source connection ID we sent in the Retry packet,
+ // instead of changing it again.
+ let scid = hdr.dcid.clone();
- debug!(
- "New connection: dcid={} scid={}",
- hex_dump(&hdr.dcid),
- hex_dump(&scid)
- );
+ debug!("New connection: dcid={:?} scid={:?}", hdr.dcid, scid);
- let conn = quiche::accept(&scid, odcid, &mut config).unwrap();
+ let conn =
+ quiche::accept(&scid, odcid.as_ref(), from, &mut config)
+ .unwrap();
let client = Client {
conn,
partial_responses: HashMap::new(),
};
- clients.insert(scid.to_vec(), (src, client));
+ clients.insert(scid.clone(), client);
- clients.get_mut(&scid[..]).unwrap()
+ clients.get_mut(&scid).unwrap()
} else {
match clients.get_mut(&hdr.dcid) {
Some(v) => v,
- None => clients.get_mut(conn_id).unwrap(),
+ None => clients.get_mut(&conn_id).unwrap(),
}
};
+ 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) => {
@@ -325,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) => {
@@ -343,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;
@@ -358,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() {
@@ -407,7 +411,7 @@ fn mint_token(hdr: &quiche::Header, src: &net::SocketAddr) -> Vec<u8> {
/// authenticate of the token. *It should not be used in production system*.
fn validate_token<'a>(
src: &net::SocketAddr, token: &'a [u8],
-) -> Option<&'a [u8]> {
+) -> Option<quiche::ConnectionId<'a>> {
if token.len() < 6 {
return None;
}
@@ -427,9 +431,7 @@ fn validate_token<'a>(
return None;
}
- let token = &token[addr.len()..];
-
- Some(&token[..])
+ Some(quiche::ConnectionId::from_ref(&token[addr.len()..]))
}
/// Handles incoming HTTP/0.9 requests.
@@ -503,6 +505,8 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
Err(quiche::Error::Done) => 0,
Err(e) => {
+ client.partial_responses.remove(&stream_id);
+
error!("{} stream send failed {:?}", conn.trace_id(), e);
return;
},
@@ -514,9 +518,3 @@ fn handle_writable(client: &mut Client, stream_id: u64) {
client.partial_responses.remove(&stream_id);
}
}
-
-fn hex_dump(buf: &[u8]) -> String {
- let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
-
- vec.join("")
-}