23const QuicPacketKeys *open_keys(QuicConn *qc,
int level)
25 if (level == QuicEnc::QUIC_ENC_INITIAL)
26 return &qc->initial.client;
27 return quic_tls_keys(&qc->tls, level,
false);
29const QuicPacketKeys *seal_keys(QuicConn *qc,
int level)
31 if (level == QuicEnc::QUIC_ENC_INITIAL)
32 return &qc->initial.server;
33 return quic_tls_keys(&qc->tls, level,
true);
37QuicStream *stream_get(QuicConn *qc, uint64_t
id,
bool create)
39 QuicStream *free_slot =
nullptr;
40 for (
size_t i = 0; i < DETWS_QUIC_MAX_STREAMS; i++)
42 if (qc->streams[i].id ==
id && qc->streams[i].id != UINT64_MAX)
43 return &qc->streams[i];
44 if (!free_slot && qc->streams[i].id == UINT64_MAX)
45 free_slot = &qc->streams[i];
47 if (!create || !free_slot)
49 memset(free_slot, 0,
sizeof(*free_slot));
55void quic_conn_init(QuicConn *qc,
const QuicTlsConfig *cfg,
const uint8_t *odcid, uint8_t odcid_len,
56 const uint8_t *peer_scid, uint8_t peer_scid_len,
const uint8_t *our_scid, uint8_t our_scid_len,
57 const QuicConnCallbacks *cb)
59 memset(qc, 0,
sizeof(*qc));
60 memcpy(qc->odcid, odcid, odcid_len);
61 qc->odcid_len = odcid_len;
62 memcpy(qc->dcid, peer_scid, peer_scid_len);
63 qc->dcid_len = peer_scid_len;
64 memcpy(qc->scid, our_scid, our_scid_len);
65 qc->scid_len = our_scid_len;
69 quic_derive_initial_secrets(odcid, odcid_len, &qc->initial);
71 for (
int i = 0; i < 3; i++)
73 qc->space[i].largest_acked = -1;
74 qc->space[i].last_ae_pn = -1;
76 for (
size_t i = 0; i < DETWS_QUIC_MAX_STREAMS; i++)
77 qc->streams[i].id = UINT64_MAX;
80 QuicTlsConfig c = *cfg;
81 c.params.has_original_dcid =
true;
82 memcpy(c.params.original_dcid, odcid, odcid_len);
83 c.params.original_dcid_len = odcid_len;
84 c.params.has_initial_scid =
true;
85 memcpy(c.params.initial_scid, our_scid, our_scid_len);
86 c.params.initial_scid_len = our_scid_len;
87 quic_tls_server_init(&qc->tls, &c);
95void queue_close(QuicConn *qc, uint64_t error_code, uint64_t frame_type,
int level)
97 if (qc->close_queued || qc->closed)
99 qc->close_queued =
true;
100 qc->close_error = error_code;
101 qc->close_frame_type = frame_type;
102 qc->close_level = (uint8_t)level;
105void handle_crypto(QuicConn *qc,
int level,
const QuicFrame *f)
107 QuicPnSpace *s = &qc->space[level];
108 uint64_t want = s->crypto_rx_off;
109 if (f->crypto.offset > want)
111 if (f->crypto.offset + f->crypto.length <= want)
113 size_t skip = (size_t)(want - f->crypto.offset);
114 const uint8_t *nd = f->crypto.data + skip;
115 size_t nl = (size_t)(f->crypto.length - skip);
116 if (s->crypto_rx_have + nl >
sizeof(s->crypto_rx))
117 nl =
sizeof(s->crypto_rx) - s->crypto_rx_have;
118 memcpy(s->crypto_rx + s->crypto_rx_have, nd, nl);
119 s->crypto_rx_have += nl;
120 s->crypto_rx_off += nl;
122 size_t used = quic_tls_recv_crypto(&qc->tls, level, s->crypto_rx, s->crypto_rx_have);
125 memmove(s->crypto_rx, s->crypto_rx + used, s->crypto_rx_have - used);
126 s->crypto_rx_have -= used;
130 if (qc->tls.state == QtlsState::QTLS_FAILED)
132 queue_close(qc, QuicErr::QUIC_ERR_CRYPTO_BASE + qc->tls.alert, QuicFrameType::QUIC_FT_CRYPTO, level);
138 if (qc->tls.state == QtlsState::QTLS_DONE && !qc->handshake_done_sent && !qc->handshake_done_queued)
140 qc->handshake_done_queued =
true;
141 qc->address_validated =
true;
142 if (qc->cb.on_handshake_done)
143 qc->cb.on_handshake_done(qc->cb.app, qc);
147void handle_stream(QuicConn *qc,
const QuicFrame *f)
149 QuicStream *st = stream_get(qc, f->stream.id,
true);
152 uint64_t want = st->rx_off;
153 if (f->stream.offset > want)
155 if (f->stream.offset + f->stream.length > want)
157 size_t skip = (size_t)(want - f->stream.offset);
158 const uint8_t *nd = f->stream.data + skip;
159 size_t nl = (size_t)(f->stream.length - skip);
160 if (nl >
sizeof(st->rx))
166 if (qc->cb.on_stream_data)
167 qc->cb.on_stream_data(qc->cb.app, qc, st->id, nd, nl, st->rx_fin);
170 if (f->stream.fin && f->stream.offset + f->stream.length == want && !st->rx_fin)
173 if (qc->cb.on_stream_data)
174 qc->cb.on_stream_data(qc->cb.app, qc, st->id,
nullptr, 0,
true);
179bool process_frames(QuicConn *qc,
int level,
const uint8_t *p,
size_t len,
bool *ack_eliciting)
184 if (p[off] == QuicFrameType::QUIC_FT_PADDING)
190 size_t n = quic_frame_parse(p + off, len - off, &f);
194 queue_close(qc, QuicErr::QUIC_ERR_FRAME_ENCODING, 0, level);
199 if (f.type != QuicFrameType::QUIC_FT_ACK && f.type != QuicFrameType::QUIC_FT_ACK_ECN &&
200 f.type != QuicFrameType::QUIC_FT_CONNECTION_CLOSE && f.type != QuicFrameType::QUIC_FT_CONNECTION_CLOSE_APP)
201 *ack_eliciting =
true;
205 case QuicFrameType::QUIC_FT_CRYPTO:
206 handle_crypto(qc, level, &f);
208 case QuicFrameType::QUIC_FT_ACK:
209 case QuicFrameType::QUIC_FT_ACK_ECN:
210 if ((int64_t)f.ack.largest > qc->space[level].largest_acked)
212 qc->space[level].largest_acked = (int64_t)f.ack.largest;
215 qc->pto_armed =
false;
218 case QuicFrameType::QUIC_FT_CONNECTION_CLOSE:
219 case QuicFrameType::QUIC_FT_CONNECTION_CLOSE_APP:
223 case QuicFrameType::QUIC_FT_HANDSHAKE_DONE:
225 case QuicFrameType::QUIC_FT_MAX_DATA:
226 case QuicFrameType::QUIC_FT_PING:
229 if (f.type >= QuicFrameType::QUIC_FT_STREAM && f.type <= QuicFrameType::QUIC_FT_STREAM + 7)
230 handle_stream(qc, &f);
238bool skip_initial_token(
const uint8_t *dg,
size_t len,
size_t *off)
240 uint64_t tok_len = 0;
242 if (!quic_varint_decode(dg + *off, len - *off, &tok_len, &c))
244 *off += c + (size_t)tok_len;
250bool parse_packet_header(
const QuicConn *qc,
const uint8_t *dg,
size_t len,
bool is_long,
int *level,
size_t *pn_offset,
251 size_t *pkt_len, uint64_t *payload_length)
256 *level = QuicEnc::QUIC_ENC_APP;
257 *pn_offset = 1 + qc->scid_len;
258 if (*pn_offset >= len)
260 *payload_length = len - *pn_offset;
266 if (!quic_parse_long_header(dg, len, &h))
268 if (h.version == 0 || h.version != QUIC_VERSION_1)
270 if (h.type == QuicLongPacket::QUIC_LP_INITIAL)
271 *level = QuicEnc::QUIC_ENC_INITIAL;
272 else if (h.type == QuicLongPacket::QUIC_LP_HANDSHAKE)
273 *level = QuicEnc::QUIC_ENC_HANDSHAKE;
277 size_t off = h.hdr_len;
278 if (*level == QuicEnc::QUIC_ENC_INITIAL && !skip_initial_token(dg, len, &off))
281 if (!quic_varint_decode(dg + off, len - off, payload_length, &c))
285 *pkt_len = *pn_offset + (size_t)*payload_length;
286 return *pkt_len <= len;
290size_t recv_packet(QuicConn *qc,
const uint8_t *dg,
size_t len)
294 bool is_long = quic_is_long_header(dg[0]);
297 size_t pn_offset = 0;
299 uint64_t payload_length = 0;
300 if (!parse_packet_header(qc, dg, len, is_long, &level, &pn_offset, &pkt_len, &payload_length))
303 const QuicPacketKeys *keys = open_keys(qc, level);
309 static uint8_t work[DETWS_QUIC_MAX_DATAGRAM];
310 static uint8_t plain[DETWS_QUIC_MAX_DATAGRAM];
311 if (pkt_len >
sizeof(work))
313 memcpy(work, dg, pkt_len);
315 size_t pt = quic_packet_unprotect(work, pn_offset, (
size_t)payload_length, qc->space[level].largest_rx, keys,
316 is_long, plain, &pn);
317 if (pt == (
size_t)-1)
318 return is_long ? pkt_len : 0;
320 if (!qc->space[level].have_rx || pn > qc->space[level].largest_rx)
321 qc->space[level].largest_rx = pn;
322 qc->space[level].have_rx =
true;
325 if (level == QuicEnc::QUIC_ENC_HANDSHAKE)
327 qc->address_validated =
true;
328 qc->space[QuicEnc::QUIC_ENC_INITIAL].discarded =
true;
331 bool ack_eliciting =
false;
332 process_frames(qc, level, plain, pt, &ack_eliciting);
334 qc->space[level].ack_eliciting_rx =
true;
340bool quic_conn_recv(QuicConn *qc,
const uint8_t *datagram,
size_t len)
344 qc->recv_bytes += len;
349 size_t n = recv_packet(qc, datagram + off, len - off);
362size_t build_ack_frame(QuicPnSpace *s, uint8_t *buf,
size_t cap)
364 if (!s->ack_eliciting_rx || !s->have_rx)
366 size_t n = quic_build_ack(buf, cap, s->largest_rx, 0, s->largest_rx);
368 s->ack_eliciting_rx =
false;
374size_t build_crypto_frame(
const QuicConn *qc,
int level, QuicPnSpace *s, uint8_t *buf,
size_t cap,
bool *ae)
376 if (level != QuicEnc::QUIC_ENC_INITIAL && level != QuicEnc::QUIC_ENC_HANDSHAKE)
379 const uint8_t *flight = quic_tls_flight(&qc->tls, level, &flen);
380 if (!flight || s->crypto_tx_off >= flen)
382 size_t remain = flen - (size_t)s->crypto_tx_off;
384 size_t room = (cap > 20) ? (cap - 20) : 0;
385 size_t take = remain < room ? remain : room;
388 size_t n = quic_build_crypto(buf, cap, s->crypto_tx_off, flight + s->crypto_tx_off, take);
391 s->crypto_tx_off += take;
398size_t build_app_frames(QuicConn *qc,
int level, uint8_t *buf,
size_t cap,
bool *ae)
400 if (level != QuicEnc::QUIC_ENC_APP)
403 if (qc->handshake_done_queued)
405 size_t n = quic_build_handshake_done(buf + p, cap - p);
409 qc->handshake_done_queued =
false;
410 qc->handshake_done_sent =
true;
414 for (
size_t i = 0; i < DETWS_QUIC_MAX_STREAMS; i++)
416 QuicStream *st = &qc->streams[i];
417 if (st->id == UINT64_MAX)
419 bool more = st->tx_sent < st->tx_have;
420 bool fin_due = st->tx_fin && !st->tx_fin_sent && st->tx_sent == st->tx_have;
421 if (!more && !fin_due)
423 size_t room = (cap - p > 24) ? (cap - p - 24) : 0;
424 size_t remain = st->tx_have - st->tx_sent;
425 size_t take = remain < room ? remain : room;
426 bool fin = st->tx_fin && (st->tx_sent + take == st->tx_have);
427 size_t n = quic_build_stream(buf + p, cap - p, st->id, st->tx_off, st->tx + st->tx_sent, take, fin);
433 st->tx_fin_sent = st->tx_fin_sent || fin;
443size_t build_frames(QuicConn *qc,
int level, uint8_t *buf,
size_t cap,
bool *ae)
445 QuicPnSpace *s = &qc->space[level];
452 if (qc->close_queued && !qc->close_sent)
453 return quic_build_connection_close(buf, cap, qc->close_error, qc->close_frame_type,
nullptr, 0);
455 p += build_ack_frame(s, buf + p, cap - p);
456 p += build_crypto_frame(qc, level, s, buf + p, cap - p, ae);
457 p += build_app_frames(qc, level, buf + p, cap - p, ae);
462uint8_t level_lp_type(
int level)
464 return level == QuicEnc::QUIC_ENC_INITIAL ? QuicLongPacket::QUIC_LP_INITIAL : QuicLongPacket::QUIC_LP_HANDSHAKE;
468size_t build_packet(QuicConn *qc,
int level, uint8_t *out,
size_t cap)
470 QuicPnSpace *s = &qc->space[level];
473 const QuicPacketKeys *keys = seal_keys(qc, level);
477 uint8_t frames[DETWS_QUIC_MAX_DATAGRAM];
479 size_t frame_len = build_frames(qc, level, frames,
sizeof(frames), &ae);
483 uint64_t pn = s->next_pn;
484 uint8_t pn_len = quic_pn_length(pn, s->largest_acked);
485 bool is_long = (level != QuicEnc::QUIC_ENC_APP);
490 if ((
size_t)pn_len + frame_len < 4)
492 size_t pad = 4 - pn_len - frame_len;
493 memset(frames + frame_len, 0, pad);
501 size_t hn = quic_build_long_header(out, cap, level_lp_type(level), QUIC_VERSION_1, qc->dcid, qc->dcid_len,
502 qc->scid, qc->scid_len, pn_len);
506 if (level == QuicEnc::QUIC_ENC_INITIAL)
508 size_t n = quic_varint_encode(out + p, cap - p, 0);
513 uint64_t length = (uint64_t)pn_len + frame_len + QUIC_AEAD_TAG_LEN;
514 size_t n = quic_varint_encode(out + p, cap - p, length);
522 if (1 + qc->dcid_len > cap)
524 out[0] = (uint8_t)(0x40 | (pn_len - 1));
525 memcpy(out + 1, qc->dcid, qc->dcid_len);
526 p = 1 + qc->dcid_len;
529 size_t pn_offset = p;
533 if (cap - p < (
size_t)pn_len + frame_len + QUIC_AEAD_TAG_LEN)
536 for (uint8_t i = 0; i < pn_len; i++)
537 out[pn_offset + i] = (uint8_t)(pn >> (8 * (pn_len - 1 - i)));
540 memcpy(out + p, frames, frame_len);
542 size_t total = quic_packet_protect(out, cap, pn_offset, pn_len, pn, frame_len, keys, is_long);
546 s->last_ae_pn = (int64_t)pn;
553int quic_highest_sealed_level(QuicConn *qc)
555 for (
int l = QuicEnc::QUIC_ENC_APP; l >= QuicEnc::QUIC_ENC_INITIAL; l--)
556 if (!qc->space[l].discarded && seal_keys(qc, l))
558 return QuicEnc::QUIC_ENC_INITIAL;
562size_t quic_conn_send(QuicConn *qc, uint8_t *out,
size_t cap)
564 if (qc->closed && !qc->draining)
570 if (!qc->address_validated && qc->sent_bytes >= 3 * qc->recv_bytes)
572 if (cap > DETWS_QUIC_MAX_DATAGRAM)
573 cap = DETWS_QUIC_MAX_DATAGRAM;
578 if (qc->close_queued && !qc->close_sent)
582 int level = qc->close_level;
583 if (level < QuicEnc::QUIC_ENC_INITIAL || level > QuicEnc::QUIC_ENC_APP || qc->space[level].discarded ||
584 !seal_keys(qc, level))
585 level = quic_highest_sealed_level(qc);
586 size_t n = build_packet(qc, level, out, cap);
589 qc->close_sent =
true;
598 for (
int level = QuicEnc::QUIC_ENC_INITIAL; level <= QuicEnc::QUIC_ENC_APP; level++)
600 size_t n = build_packet(qc, level, out + dg, cap - dg);
605 qc->sent_bytes += dg;
612uint32_t pto_period(uint8_t count)
614 uint32_t p = DETWS_QUIC_PTO_MS;
615 for (uint8_t i = 0; i < count && p < (1u << 30); i++)
621bool space_outstanding(
const QuicPnSpace *s)
623 return !s->discarded && s->last_ae_pn >= 0 && s->largest_acked < s->last_ae_pn;
627void quic_conn_on_timeout(QuicConn *qc, uint32_t now_ms)
635 bool outstanding = space_outstanding(&qc->space[QuicEnc::QUIC_ENC_INITIAL]) ||
636 space_outstanding(&qc->space[QuicEnc::QUIC_ENC_HANDSHAKE]) ||
637 space_outstanding(&qc->space[QuicEnc::QUIC_ENC_APP]);
640 qc->pto_armed =
false;
646 qc->pto_armed =
true;
647 qc->pto_deadline_ms = now_ms + pto_period(qc->pto_count);
650 if ((int32_t)(now_ms - qc->pto_deadline_ms) < 0)
655 for (
int level = QuicEnc::QUIC_ENC_INITIAL; level <= QuicEnc::QUIC_ENC_HANDSHAKE; level++)
656 if (space_outstanding(&qc->space[level]))
657 qc->space[level].crypto_tx_off = 0;
658 if (space_outstanding(&qc->space[QuicEnc::QUIC_ENC_APP]))
662 if (qc->handshake_done_sent)
664 qc->handshake_done_queued =
true;
665 qc->handshake_done_sent =
false;
667 for (
size_t i = 0; i < DETWS_QUIC_MAX_STREAMS; i++)
669 QuicStream *st = &qc->streams[i];
670 if (st->id == UINT64_MAX)
674 st->tx_fin_sent =
false;
677 if (qc->pto_count < 8)
679 qc->pto_deadline_ms = now_ms + pto_period(qc->pto_count);
682size_t quic_conn_stream_send(QuicConn *qc, uint64_t stream_id,
const uint8_t *data,
size_t len,
bool fin)
684 QuicStream *st = stream_get(qc, stream_id,
true);
687 size_t room =
sizeof(st->tx) - st->tx_have;
688 size_t take = len < room ? len : room;
689 memcpy(st->tx + st->tx_have, data, take);
691 if (fin && take == len)
696void quic_conn_close(QuicConn *qc, uint64_t error_code)
699 int level = quic_highest_sealed_level(qc);
700 queue_close(qc, error_code, 0, level);
703bool quic_conn_established(
const QuicConn *qc)
705 return qc->tls.state == QtlsState::QTLS_DONE;
708bool quic_conn_is_closed(
const QuicConn *qc)
710 return qc->closed || qc->draining;
AES-128 block cipher and AEAD_AES_128_GCM (RFC 5116 / NIST SP 800-38D).
Stateful QUIC v1 server connection engine (RFC 9000 / RFC 9001).
QUIC frame parsing and building (RFC 9000 sec 19).
QUIC packet headers and packet-number coding (RFC 9000 sec 17).
QUIC variable-length integer coding (RFC 9000 sec 16).