23static_assert(PC_QUIC_MAX_DATAGRAM < PC_QUIC_STREAM_RX,
24 "PC_QUIC_STREAM_RX must exceed PC_QUIC_MAX_DATAGRAM: one STREAM frame's payload is bounded by the "
25 "datagram, and handle_stream relies on that to deliver it without clamping");
31static_assert(PC_QUIC_MAX_DATAGRAM >= 1200,
32 "PC_QUIC_MAX_DATAGRAM must be at least the RFC 9000 sec 14.1 minimum of 1200 octets, which is also "
33 "what lets build_frames assume every frame builder has room");
39QuicPacketKeys *open_keys(QuicConn *qc,
int level)
41 if (level == QuicEnc::QUIC_ENC_INITIAL)
43 return &qc->initial.client;
45 return pc_quic_tls_keys(&qc->tls, level,
false);
47QuicPacketKeys *seal_keys(QuicConn *qc,
int level)
49 if (level == QuicEnc::QUIC_ENC_INITIAL)
51 return &qc->initial.server;
53 return pc_quic_tls_keys(&qc->tls, level,
true);
57QuicStream *stream_get(QuicConn *qc, uint64_t
id,
bool create)
59 QuicStream *free_slot =
nullptr;
60 for (
size_t i = 0; i < PC_QUIC_MAX_STREAMS; i++)
62 if (qc->streams[i].id ==
id && qc->streams[i].id != UINT64_MAX)
64 return &qc->streams[i];
66 if (!free_slot && qc->streams[i].id == UINT64_MAX)
68 free_slot = &qc->streams[i];
71 if (!create || !free_slot)
75 memset(free_slot, 0,
sizeof(*free_slot));
81void pc_quic_conn_init(QuicConn *qc,
const QuicTlsConfig *cfg,
const uint8_t *odcid, uint8_t odcid_len,
82 const uint8_t *peer_scid, uint8_t peer_scid_len,
const uint8_t *our_scid, uint8_t our_scid_len,
83 const QuicConnCallbacks *cb)
85 memset(qc, 0,
sizeof(*qc));
86 memcpy(qc->odcid, odcid, odcid_len);
87 qc->odcid_len = odcid_len;
88 memcpy(qc->dcid, peer_scid, peer_scid_len);
89 qc->dcid_len = peer_scid_len;
90 memcpy(qc->scid, our_scid, our_scid_len);
91 qc->scid_len = our_scid_len;
97 pc_quic_derive_initial_secrets(odcid, odcid_len, &qc->initial);
99 for (
int i = 0; i < 3; i++)
101 qc->space[i].largest_acked = -1;
102 qc->space[i].last_ae_pn = -1;
104 for (
size_t i = 0; i < PC_QUIC_MAX_STREAMS; i++)
106 qc->streams[i].id = UINT64_MAX;
110 QuicTlsConfig c = *cfg;
111 c.params.has_original_dcid =
true;
112 memcpy(c.params.original_dcid, odcid, odcid_len);
113 c.params.original_dcid_len = odcid_len;
114 c.params.has_initial_scid =
true;
115 memcpy(c.params.initial_scid, our_scid, our_scid_len);
116 c.params.initial_scid_len = our_scid_len;
117 pc_quic_tls_server_init(&qc->tls, &c);
125void queue_close(QuicConn *qc, uint64_t error_code, uint64_t frame_type,
int level)
127 if (qc->close_queued || qc->closed)
131 qc->close_queued =
true;
132 qc->close_error = error_code;
133 qc->close_frame_type = frame_type;
134 qc->close_level = (uint8_t)level;
137void handle_crypto(QuicConn *qc,
int level,
const QuicFrame *f)
139 QuicPnSpace *s = &qc->space[level];
140 uint64_t want = s->crypto_rx_off;
141 if (f->crypto.offset > want)
145 if (f->crypto.offset + f->crypto.length <= want)
149 size_t skip = (size_t)(want - f->crypto.offset);
150 const uint8_t *nd = f->crypto.data + skip;
151 size_t nl = (size_t)(f->crypto.length - skip);
152 if (s->crypto_rx_have + nl >
sizeof(s->crypto_rx))
154 nl =
sizeof(s->crypto_rx) - s->crypto_rx_have;
156 memcpy(s->crypto_rx + s->crypto_rx_have, nd, nl);
157 s->crypto_rx_have += nl;
158 s->crypto_rx_off += nl;
160 size_t used = pc_quic_tls_recv_crypto(&qc->tls, level, s->crypto_rx, s->crypto_rx_have);
163 memmove(s->crypto_rx, s->crypto_rx + used, s->crypto_rx_have - used);
164 s->crypto_rx_have -= used;
168 if (qc->tls.state == QtlsState::QTLS_FAILED)
170 queue_close(qc, QuicErr::QUIC_ERR_CRYPTO_BASE + qc->tls.alert, QuicFrameType::QUIC_FT_CRYPTO, level);
176 if (qc->tls.state == QtlsState::QTLS_DONE && !qc->handshake_done_sent && !qc->handshake_done_queued)
178 qc->handshake_done_queued =
true;
179 qc->address_validated =
true;
180 if (qc->cb.on_handshake_done)
182 qc->cb.on_handshake_done(qc->cb.app, qc);
187void handle_stream(QuicConn *qc,
const QuicFrame *f)
189 QuicStream *st = stream_get(qc, f->stream.id,
true);
194 uint64_t want = st->rx_off;
195 if (f->stream.offset > want)
199 if (f->stream.offset + f->stream.length > want)
201 size_t skip = (size_t)(want - f->stream.offset);
202 const uint8_t *nd = f->stream.data + skip;
203 size_t nl = (size_t)(f->stream.length - skip);
204 if (nl >
sizeof(st->rx))
214 if (qc->cb.on_stream_data)
216 qc->cb.on_stream_data(qc->cb.app, qc, st->id, nd, nl, st->rx_fin);
220 if (f->stream.fin && f->stream.offset + f->stream.length == want && !st->rx_fin)
223 if (qc->cb.on_stream_data)
225 qc->cb.on_stream_data(qc->cb.app, qc, st->id,
nullptr, 0,
true);
231bool process_frames(QuicConn *qc,
int level,
const uint8_t *p,
size_t len,
bool *ack_eliciting)
236 if (p[off] == QuicFrameType::QUIC_FT_PADDING)
242 size_t n = pc_quic_frame_parse(p + off, len - off, &f);
246 queue_close(qc, QuicErr::QUIC_ERR_FRAME_ENCODING, 0, level);
251 if (f.type != QuicFrameType::QUIC_FT_ACK && f.type != QuicFrameType::QUIC_FT_ACK_ECN &&
252 f.type != QuicFrameType::QUIC_FT_CONNECTION_CLOSE && f.type != QuicFrameType::QUIC_FT_CONNECTION_CLOSE_APP)
254 *ack_eliciting =
true;
259 case QuicFrameType::QUIC_FT_CRYPTO:
260 handle_crypto(qc, level, &f);
262 case QuicFrameType::QUIC_FT_ACK:
263 case QuicFrameType::QUIC_FT_ACK_ECN:
264 if ((int64_t)f.ack.largest > qc->space[level].largest_acked)
266 qc->space[level].largest_acked = (int64_t)f.ack.largest;
269 qc->pto_armed =
false;
272 case QuicFrameType::QUIC_FT_CONNECTION_CLOSE:
273 case QuicFrameType::QUIC_FT_CONNECTION_CLOSE_APP:
277 case QuicFrameType::QUIC_FT_HANDSHAKE_DONE:
279 case QuicFrameType::QUIC_FT_MAX_DATA:
280 case QuicFrameType::QUIC_FT_PING:
283 if (f.type >= QuicFrameType::QUIC_FT_STREAM && f.type <= QuicFrameType::QUIC_FT_STREAM + 7)
285 handle_stream(qc, &f);
294bool skip_initial_token(
const uint8_t *dg,
size_t len,
size_t *off)
296 uint64_t tok_len = 0;
298 if (!pc_quic_varint_decode(dg + *off, len - *off, &tok_len, &c))
302 *off += c + (size_t)tok_len;
308bool parse_packet_header(
const QuicConn *qc,
const uint8_t *dg,
size_t len,
bool is_long,
int *level,
size_t *pn_offset,
309 size_t *pkt_len, uint64_t *payload_length)
314 *level = QuicEnc::QUIC_ENC_APP;
315 *pn_offset = 1 + qc->scid_len;
316 if (*pn_offset >= len)
320 *payload_length = len - *pn_offset;
326 if (!pc_quic_parse_long_header(dg, len, &h))
330 if (h.version == 0 || h.version != QUIC_VERSION_1)
334 if (h.type == QuicLongPacket::QUIC_LP_INITIAL)
336 *level = QuicEnc::QUIC_ENC_INITIAL;
338 else if (h.type == QuicLongPacket::QUIC_LP_HANDSHAKE)
340 *level = QuicEnc::QUIC_ENC_HANDSHAKE;
347 size_t off = h.hdr_len;
348 if (*level == QuicEnc::QUIC_ENC_INITIAL && !skip_initial_token(dg, len, &off))
353 if (!pc_quic_varint_decode(dg + off, len - off, payload_length, &c))
359 *pkt_len = *pn_offset + (size_t)*payload_length;
360 return *pkt_len <= len;
364size_t recv_packet(QuicConn *qc,
const uint8_t *dg,
size_t len)
370 bool is_long = pc_quic_is_long_header(dg[0]);
373 size_t pn_offset = 0;
375 uint64_t payload_length = 0;
376 if (!parse_packet_header(qc, dg, len, is_long, &level, &pn_offset, &pkt_len, &payload_length))
381 QuicPacketKeys *
const keys = open_keys(qc, level);
389 static uint8_t work[PC_QUIC_MAX_DATAGRAM];
390 static uint8_t plain[PC_QUIC_MAX_DATAGRAM];
391 if (pkt_len >
sizeof(work))
395 memcpy(work, dg, pkt_len);
397 size_t pt = pc_quic_packet_unprotect(work, pn_offset, (
size_t)payload_length, qc->space[level].largest_rx, *keys,
398 is_long, plain, &pn);
399 if (pt == (
size_t)-1)
401 return is_long ? pkt_len : 0;
404 if (!qc->space[level].have_rx || pn > qc->space[level].largest_rx)
406 qc->space[level].largest_rx = pn;
408 qc->space[level].have_rx =
true;
411 if (level == QuicEnc::QUIC_ENC_HANDSHAKE)
413 qc->address_validated =
true;
414 qc->space[QuicEnc::QUIC_ENC_INITIAL].discarded =
true;
417 bool ack_eliciting =
false;
418 process_frames(qc, level, plain, pt, &ack_eliciting);
421 qc->space[level].ack_eliciting_rx =
true;
428bool pc_quic_conn_recv(QuicConn *qc,
const uint8_t *datagram,
size_t len)
434 qc->recv_bytes += len;
439 size_t n = recv_packet(qc, datagram + off, len - off);
454size_t build_ack_frame(QuicPnSpace *s, uint8_t *buf,
size_t cap)
456 if (!s->ack_eliciting_rx || !s->have_rx)
460 size_t n = pc_quic_build_ack(buf, cap, s->largest_rx, 0, s->largest_rx);
463 s->ack_eliciting_rx =
false;
470size_t build_crypto_frame(
const QuicConn *qc,
int level, QuicPnSpace *s, uint8_t *buf,
size_t cap,
bool *ae)
472 if (level != QuicEnc::QUIC_ENC_INITIAL && level != QuicEnc::QUIC_ENC_HANDSHAKE)
477 const uint8_t *flight = pc_quic_tls_flight(&qc->tls, level, &flen);
478 if (!flight || s->crypto_tx_off >= flen)
482 size_t remain = flen - (size_t)s->crypto_tx_off;
484 size_t room = (cap > 20) ? (cap - 20) : 0;
485 size_t take = remain < room ? remain : room;
490 size_t n = pc_quic_build_crypto(buf, cap, s->crypto_tx_off, flight + s->crypto_tx_off, take);
493 s->crypto_tx_off += take;
500size_t build_app_frames(QuicConn *qc,
int level, uint8_t *buf,
size_t cap,
bool *ae)
502 if (level != QuicEnc::QUIC_ENC_APP)
507 if (qc->handshake_done_queued)
509 size_t n = pc_quic_build_handshake_done(buf + p, cap - p);
514 qc->handshake_done_queued =
false;
515 qc->handshake_done_sent =
true;
519 for (
size_t i = 0; i < PC_QUIC_MAX_STREAMS; i++)
521 QuicStream *st = &qc->streams[i];
522 if (st->id == UINT64_MAX)
526 bool more = st->tx_sent < st->tx_have;
527 bool fin_due = st->tx_fin && !st->tx_fin_sent && st->tx_sent == st->tx_have;
528 if (!more && !fin_due)
532 size_t room = (cap - p > 24) ? (cap - p - 24) : 0;
533 size_t remain = st->tx_have - st->tx_sent;
534 size_t take = remain < room ? remain : room;
535 bool fin = st->tx_fin && (st->tx_sent + take == st->tx_have);
536 size_t n = pc_quic_build_stream(buf + p, cap - p, st->id, st->tx_off, st->tx + st->tx_sent, take, fin);
542 st->tx_fin_sent = st->tx_fin_sent || fin;
552size_t build_frames(QuicConn *qc,
int level, uint8_t *buf,
size_t cap,
bool *ae)
554 QuicPnSpace *s = &qc->space[level];
561 if (qc->close_queued && !qc->close_sent)
563 return pc_quic_build_connection_close(buf, cap, qc->close_error, qc->close_frame_type,
nullptr, 0);
566 p += build_ack_frame(s, buf + p, cap - p);
567 p += build_crypto_frame(qc, level, s, buf + p, cap - p, ae);
568 p += build_app_frames(qc, level, buf + p, cap - p, ae);
573uint8_t level_lp_type(
int level)
575 return level == QuicEnc::QUIC_ENC_INITIAL ? QuicLongPacket::QUIC_LP_INITIAL : QuicLongPacket::QUIC_LP_HANDSHAKE;
579size_t packet_overhead(
const QuicConn *qc,
bool is_long, uint8_t pn_len)
581 size_t overhead = (size_t)PC_AES128GCM_TAG_LEN + pn_len;
586 overhead += 7u + qc->dcid_len + qc->scid_len + 1u + 4u;
590 overhead += 1u + qc->dcid_len;
596size_t build_packet(QuicConn *qc,
int level, uint8_t *out,
size_t cap)
598 QuicPnSpace *s = &qc->space[level];
603 QuicPacketKeys *
const keys = seal_keys(qc, level);
609 uint64_t pn = s->next_pn;
610 uint8_t pn_len = pc_quic_pn_length(pn, s->largest_acked);
611 bool is_long = (level != QuicEnc::QUIC_ENC_APP);
621 size_t overhead = packet_overhead(qc, is_long, pn_len);
626 size_t budget = cap - overhead;
628 uint8_t frames[PC_QUIC_MAX_DATAGRAM];
632 if (budget >
sizeof(frames))
634 budget =
sizeof(frames);
643 size_t frame_len = build_frames(qc, level, frames, budget, &ae);
652 if ((
size_t)pn_len + frame_len < 4)
654 size_t pad = 4 - pn_len - frame_len;
655 memset(frames + frame_len, 0, pad);
663 size_t hn = pc_quic_build_long_header(out, cap, level_lp_type(level), QUIC_VERSION_1, qc->dcid, qc->dcid_len,
664 qc->scid, qc->scid_len, pn_len);
670 if (level == QuicEnc::QUIC_ENC_INITIAL)
672 size_t n = pc_quic_varint_encode(out + p, cap - p, 0);
679 uint64_t length = (uint64_t)pn_len + frame_len + PC_AES128GCM_TAG_LEN;
680 size_t n = pc_quic_varint_encode(out + p, cap - p, length);
690 if (1 + qc->dcid_len > cap)
694 out[0] = (uint8_t)(0x40 | (pn_len - 1));
695 memcpy(out + 1, qc->dcid, qc->dcid_len);
696 p = 1 + qc->dcid_len;
699 size_t pn_offset = p;
705 if (cap - p < (
size_t)pn_len + frame_len + PC_AES128GCM_TAG_LEN)
710 for (uint8_t i = 0; i < pn_len; i++)
712 out[pn_offset + i] = (uint8_t)(pn >> (8 * (pn_len - 1 - i)));
716 memcpy(out + p, frames, frame_len);
718 size_t total = pc_quic_packet_protect(out, cap, pn_offset, pn_len, pn, frame_len, *keys, is_long);
725 s->last_ae_pn = (int64_t)pn;
733int pc_quic_highest_sealed_level(QuicConn *qc)
735 for (
int l = QuicEnc::QUIC_ENC_APP; l >= QuicEnc::QUIC_ENC_INITIAL; l--)
737 if (!qc->space[l].discarded && seal_keys(qc, l))
742 return QuicEnc::QUIC_ENC_INITIAL;
746size_t pc_quic_conn_send(QuicConn *qc, uint8_t *out,
size_t cap)
748 if (qc->closed && !qc->draining)
756 if (!qc->address_validated && qc->sent_bytes >= 3 * qc->recv_bytes)
760 if (cap > PC_QUIC_MAX_DATAGRAM)
762 cap = PC_QUIC_MAX_DATAGRAM;
768 if (qc->close_queued && !qc->close_sent)
772 int level = qc->close_level;
775 if (level < QuicEnc::QUIC_ENC_INITIAL || level > QuicEnc::QUIC_ENC_APP || qc->space[level].discarded ||
776 !seal_keys(qc, level))
778 level = pc_quic_highest_sealed_level(qc);
781 size_t n = build_packet(qc, level, out, cap);
784 qc->close_sent =
true;
793 for (
int level = QuicEnc::QUIC_ENC_INITIAL; level <= QuicEnc::QUIC_ENC_APP; level++)
795 size_t n = build_packet(qc, level, out + dg, cap - dg);
802 qc->sent_bytes += dg;
809uint32_t pto_period(uint8_t count)
811 uint32_t p = PC_QUIC_PTO_MS;
812 for (uint8_t i = 0; i < count && p < (1u << 30); i++)
820bool space_outstanding(
const QuicPnSpace *s)
822 return !s->discarded && s->last_ae_pn >= 0 && s->largest_acked < s->last_ae_pn;
826void pc_quic_conn_on_timeout(QuicConn *qc, uint32_t now_ms)
836 bool outstanding = space_outstanding(&qc->space[QuicEnc::QUIC_ENC_INITIAL]) ||
837 space_outstanding(&qc->space[QuicEnc::QUIC_ENC_HANDSHAKE]) ||
838 space_outstanding(&qc->space[QuicEnc::QUIC_ENC_APP]);
841 qc->pto_armed =
false;
847 qc->pto_armed =
true;
848 qc->pto_deadline_ms = now_ms + pto_period(qc->pto_count);
851 if ((int32_t)(now_ms - qc->pto_deadline_ms) < 0)
858 for (
int level = QuicEnc::QUIC_ENC_INITIAL; level <= QuicEnc::QUIC_ENC_HANDSHAKE; level++)
860 if (space_outstanding(&qc->space[level]))
862 qc->space[level].crypto_tx_off = 0;
865 if (space_outstanding(&qc->space[QuicEnc::QUIC_ENC_APP]))
869 if (qc->handshake_done_sent)
871 qc->handshake_done_queued =
true;
872 qc->handshake_done_sent =
false;
874 for (
size_t i = 0; i < PC_QUIC_MAX_STREAMS; i++)
876 QuicStream *st = &qc->streams[i];
877 if (st->id == UINT64_MAX)
883 st->tx_fin_sent =
false;
886 if (qc->pto_count < 8)
890 qc->pto_deadline_ms = now_ms + pto_period(qc->pto_count);
893size_t pc_quic_conn_stream_send(QuicConn *qc, uint64_t stream_id,
const uint8_t *data,
size_t len,
bool fin)
895 QuicStream *st = stream_get(qc, stream_id,
true);
900 size_t room =
sizeof(st->tx) - st->tx_have;
901 size_t take = len < room ? len : room;
902 memcpy(st->tx + st->tx_have, data, take);
904 if (fin && take == len)
911void pc_quic_conn_close(QuicConn *qc, uint64_t error_code)
914 int level = pc_quic_highest_sealed_level(qc);
915 queue_close(qc, error_code, 0, level);
918bool pc_quic_conn_established(
const QuicConn *qc)
920 return qc->tls.state == QtlsState::QTLS_DONE;
923bool pc_quic_conn_is_closed(
const QuicConn *qc)
925 return qc->closed || qc->draining;
AES-128 block cipher + AEAD_AES_128_GCM (RFC 5116 / NIST SP 800-38D).