lsquic_mini_conn.c revision de46bf2f
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_mini_conn.c -- Mini connection.
4 *
5 * Mini connection is only used in server mode -- this assumption is relied
6 * upon by the code in this file.
7 *
8 * The purpose of this connection is to process incoming handshakes using
9 * minimal amount of resources until we confirm that the client is sending
10 * valid data.  Here, we only process Stream 1 data; other packets are
11 * spooled, if necessary.  When mini connection is promoted to full
12 * connection, the state, including spooled incoming packets, is transferred
13 * to the full connection.
14 *
15 * Note that mini connections do not retransmit lost packets.  This is to
16 * minimize the effect of magnification attacks.  Clients like Chrome and
17 * Opera fall back to using TCP if QUIC handshake times out.
18 */
19
20
21#include <assert.h>
22#include <errno.h>
23#include <inttypes.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/queue.h>
27
28#include "lsquic.h"
29#include "lsquic_int_types.h"
30#include "lsquic_hash.h"
31#include "lsquic_conn.h"
32#include "lsquic_rtt.h"
33#include "lsquic_mini_conn.h"
34#include "lsquic_mm.h"
35#include "lsquic_malo.h"
36#include "lsquic_packet_common.h"
37#include "lsquic_packet_gquic.h"
38#include "lsquic_packet_ietf.h"
39#include "lsquic_packet_in.h"
40#include "lsquic_packet_out.h"
41#include "lsquic_util.h"
42#include "lsquic_str.h"
43#include "lsquic_enc_sess.h"
44#include "lsquic_parse.h"
45#include "lsquic_engine_public.h"
46#include "lsquic_sfcw.h"
47#include "lsquic_varint.h"
48#include "lsquic_hq.h"
49#include "lsquic_varint.h"
50#include "lsquic_stream.h"
51#include "lsquic_rechist.h"
52#include "lsquic_ev_log.h"
53#include "lsquic_qtags.h"
54#include "lsquic_attq.h"
55#include "lsquic_alarmset.h"
56
57#define LSQUIC_LOGGER_MODULE LSQLM_MINI_CONN
58#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(&mc->mc_conn)
59#include "lsquic_logger.h"
60
61
62static const struct conn_iface mini_conn_iface_standard;
63static const struct conn_iface mini_conn_iface_standard_Q050;
64
65#if LSQUIC_KEEP_MINICONN_HISTORY
66
67static void
68mchist_append (struct mini_conn *mc, enum miniconn_history_event mh_event)
69{
70    enum miniconn_history_event prev_event;
71    mchist_idx_t idx;
72    int plus;
73
74    idx = (mc->mc_hist_idx - 1) & MCHIST_MASK;
75    plus = MCHE_PLUS == mc->mc_hist_buf[ idx ];
76    idx = (idx - plus) & MCHIST_MASK;
77    prev_event = mc->mc_hist_buf[ idx ];
78
79    if (!(prev_event == mh_event && plus))
80    {
81        if (prev_event == mh_event)
82            mh_event = MCHE_PLUS;
83        mc->mc_hist_buf[ MCHIST_MASK & mc->mc_hist_idx++ ] = mh_event;
84    }
85}
86
87
88#   define MCHIST_APPEND(mc, event) mchist_append(mc, event)
89#else
90#   define MCHIST_APPEND(mc, event)
91#endif
92
93static void
94process_deferred_packets (struct mini_conn *mc);
95
96
97/* If this is not true, highest_bit_set() may be broken */
98typedef char packno_set_is_unsigned_long[
99        (sizeof(unsigned long long) == sizeof(mconn_packno_set_t)) - 1];
100
101static unsigned
102highest_bit_set (unsigned long long sz)
103{
104#if __GNUC__
105    unsigned clz = __builtin_clzll(sz);
106    return 63 - clz;
107#else
108    unsigned long y;
109    unsigned n;
110    n = 64;
111    y = sz >> 32;     if (y) { n -= 32; sz = y; }
112    y = sz >> 16;     if (y) { n -= 16; sz = y; }
113    y = sz >>  8;     if (y) { n -=  8; sz = y; }
114    y = sz >>  4;     if (y) { n -=  4; sz = y; }
115    y = sz >>  2;     if (y) { n -=  2; sz = y; }
116    y = sz >>  1;     if (y) return 63 - n + 2;
117    return 63 - n + sz;
118#endif
119}
120
121
122static unsigned
123lowest_bit_set (unsigned v)
124{
125#if __GNUC__
126    return __builtin_ctz(v);
127#else
128    unsigned n;
129    n = 0;
130    if (0 == (v & ((1 << 16) - 1))) { n += 16; v >>= 16; }
131    if (0 == (v & ((1 <<  8) - 1))) { n +=  8; v >>=  8; }
132    if (0 == (v & ((1 <<  4) - 1))) { n +=  4; v >>=  4; }
133    if (0 == (v & ((1 <<  2) - 1))) { n +=  2; v >>=  2; }
134    if (0 == (v & ((1 <<  1) - 1))) { n +=  1;           }
135    return n;
136#endif
137}
138
139
140static int
141is_handshake_stream_id (const struct mini_conn *conn,
142                                                lsquic_stream_id_t stream_id)
143{
144    return conn->mc_conn.cn_version < LSQVER_050 && stream_id == 1;
145}
146
147
148static void
149mini_destroy_packet (struct mini_conn *mc, struct lsquic_packet_out *packet_out)
150{
151    lsquic_packet_out_destroy(packet_out, mc->mc_enpub,
152                                                    mc->mc_path.np_peer_ctx);
153}
154
155
156static int
157packet_in_is_ok (enum lsquic_version version,
158                                    const struct lsquic_packet_in *packet_in)
159{
160    size_t min_size;
161
162    if (packet_in->pi_data_sz > GQUIC_MAX_PACKET_SZ)
163    {
164        LSQ_LOG1(LSQ_LOG_DEBUG, "incoming packet too large: %hu bytes",
165                                                    packet_in->pi_data_sz);
166        return 0;
167    }
168
169    if ((1 << version) & LSQUIC_GQUIC_HEADER_VERSIONS)
170        /* This is a very lax number, it allows the server to send
171         * 64 * 200 = 12KB of output (REJ and SHLO).
172         */
173        min_size = 200;
174    else
175        /* Chrome enforces 1200-byte minimum initial packet limit */
176        min_size = IQUIC_MIN_INIT_PACKET_SZ;
177
178    if (packet_in->pi_data_sz < min_size)
179    {
180        LSQ_LOG1(LSQ_LOG_DEBUG, "incoming packet too small: %hu bytes",
181                                                    packet_in->pi_data_sz);
182        return 0;
183    }
184    return 1;
185}
186
187
188lsquic_conn_t *
189mini_conn_new (struct lsquic_engine_public *enp,
190               const struct lsquic_packet_in *packet_in,
191               enum lsquic_version version)
192{
193    struct mini_conn *mc;
194    const struct conn_iface *conn_iface;
195
196    if (!packet_in_is_ok(version, packet_in))
197        return NULL;
198    switch (version)
199    {
200    case LSQVER_050:
201        conn_iface = &mini_conn_iface_standard_Q050;
202        break;
203    default:
204        conn_iface = &mini_conn_iface_standard;
205        break;
206    }
207
208    mc = lsquic_malo_get(enp->enp_mm.malo.mini_conn);
209    if (!mc)
210    {
211        LSQ_LOG1(LSQ_LOG_WARN, "cannot allocate mini connection: %s",
212                                                            strerror(errno));
213        return NULL;
214    }
215
216    memset(mc, 0, sizeof(*mc));
217    TAILQ_INIT(&mc->mc_deferred);
218    TAILQ_INIT(&mc->mc_packets_in);
219    TAILQ_INIT(&mc->mc_packets_out);
220    mc->mc_enpub = enp;
221    mc->mc_created = packet_in->pi_received;
222    mc->mc_path.np_pack_size = packet_in->pi_data_sz;
223    mc->mc_conn.cn_cces = mc->mc_cces;
224    mc->mc_conn.cn_cces_mask = 1;
225    mc->mc_conn.cn_n_cces = sizeof(mc->mc_cces) / sizeof(mc->mc_cces[0]);
226    mc->mc_conn.cn_version = version;
227    mc->mc_conn.cn_pf = select_pf_by_ver(version);
228    mc->mc_conn.cn_esf_c = select_esf_common_by_ver(version);
229    mc->mc_conn.cn_esf.g = select_esf_gquic_by_ver(version);
230    mc->mc_conn.cn_cid = packet_in->pi_conn_id;
231    mc->mc_conn.cn_flags = LSCONN_MINI | LSCONN_SERVER;
232    mc->mc_conn.cn_if = conn_iface;
233    LSQ_DEBUG("created mini connection object");
234    MCHIST_APPEND(mc, MCHE_CREATED);
235    return &mc->mc_conn;
236}
237
238
239static int
240in_acked_range (const struct ack_info *acki, lsquic_packno_t n)  /* This is a copy */
241{
242    int in_range = 0;
243    unsigned i;
244    for (i = 0; i < acki->n_ranges; ++i)
245        in_range += acki->ranges[i].high >= n
246                 && acki->ranges[i].low  <= n;
247    return in_range > 0;
248}
249
250
251static void
252take_rtt_sample (struct mini_conn *mc, const lsquic_packet_out_t *packet_out,
253                 lsquic_time_t now, lsquic_time_t lack_delta)
254{
255    assert(packet_out->po_sent);
256    lsquic_time_t measured_rtt = now - packet_out->po_sent;
257    if (lack_delta < measured_rtt)
258    {
259        lsquic_rtt_stats_update(&mc->mc_rtt_stats, measured_rtt, lack_delta);
260        LSQ_DEBUG("srtt: %"PRIu64" usec, var: %"PRIu64,
261                        lsquic_rtt_stats_get_srtt(&mc->mc_rtt_stats),
262                        lsquic_rtt_stats_get_rttvar(&mc->mc_rtt_stats));
263    }
264}
265
266
267static unsigned
268process_ack_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
269                                        const unsigned char *p, size_t len)
270{
271    int parsed_len;
272    int n_newly_acked;
273    unsigned n;
274    lsquic_packet_out_t *packet_out, *next;
275    struct ack_info *acki;
276    lsquic_packno_t packno;
277    lsquic_time_t warn_time;
278    char buf[200];
279
280    acki = mc->mc_enpub->enp_mm.acki;
281    parsed_len = mc->mc_conn.cn_pf->pf_parse_ack_frame(p, len, acki, 0);
282    if (parsed_len < 0)
283        return 0;
284    if (empty_ack_frame(acki))
285    {
286        LSQ_DEBUG("Ignore empty ACK frame");
287        return parsed_len;
288    }
289    if (packet_in->pi_packno <= mc->mc_max_ack_packno)
290    {
291        LSQ_DEBUG("Ignore old ack (max %u)", mc->mc_max_ack_packno);
292        return parsed_len;
293    }
294
295    /* Verify ACK frame and update list of acked packet numbers: */
296    for (n = 0; n < acki->n_ranges; ++n)
297        for (packno = acki->ranges[n].low; packno <= acki->ranges[n].high;
298                                                                    ++packno)
299            if (packno > MINICONN_MAX_PACKETS ||
300                0 == (MCONN_PACKET_MASK(packno) & mc->mc_sent_packnos))
301                {
302                    warn_time = lsquic_time_now();
303                    if (0 == mc->mc_enpub->enp_last_warning[WT_ACKPARSE_MINI]
304                        || mc->mc_enpub->enp_last_warning[WT_ACKPARSE_MINI]
305                                + WARNING_INTERVAL < warn_time)
306                    {
307                        mc->mc_enpub->enp_last_warning[WT_ACKPARSE_MINI]
308                                                                = warn_time;
309                        lsquic_hexdump(p, len, buf, sizeof(buf));
310                        LSQ_WARN("packet %"PRIu64" was never sent; ACK "
311                            "frame:\n%s", packno, buf);
312                    }
313                    else
314                        LSQ_DEBUG("packet %"PRIu64" was never sent", packno);
315                    MCHIST_APPEND(mc, MCHE_UNSENT_ACKED);
316                    return 0;
317                }
318            else
319                mc->mc_acked_packnos |= MCONN_PACKET_MASK(packno);
320
321    EV_LOG_ACK_FRAME_IN(LSQUIC_LOG_CONN_ID, acki);
322    n_newly_acked = 0;
323    for (packet_out = TAILQ_FIRST(&mc->mc_packets_out); packet_out;
324                                                            packet_out = next)
325    {
326        next = TAILQ_NEXT(packet_out, po_next);
327        if (in_acked_range(acki, packet_out->po_packno))
328        {
329            ++n_newly_acked;
330            LSQ_DEBUG("Got ACK for packet %"PRIu64, packet_out->po_packno);
331            if (packet_out->po_packno == largest_acked(acki))
332                take_rtt_sample(mc, packet_out, packet_in->pi_received,
333                                                            acki->lack_delta);
334            TAILQ_REMOVE(&mc->mc_packets_out, packet_out, po_next);
335            mini_destroy_packet(mc, packet_out);
336        }
337    }
338
339    if (n_newly_acked > 0)
340        mc->mc_hsk_count = 0;
341
342    return parsed_len;
343}
344
345
346static unsigned
347process_blocked_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
348                                            const unsigned char *p, size_t len)
349{
350    lsquic_stream_id_t stream_id;
351    int parsed_len;
352    parsed_len = mc->mc_conn.cn_pf->pf_parse_blocked_frame(p, len, &stream_id);
353    if (parsed_len < 0)
354        return 0;
355    EV_LOG_BLOCKED_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_id);
356    LSQ_DEBUG("Peer reports stream %"PRIu64" as blocked", stream_id);
357    return parsed_len;
358}
359
360
361static mconn_packno_set_t
362drop_packets_out (struct mini_conn *mc)
363{
364    struct lsquic_packet_out *packet_out;
365    mconn_packno_set_t in_flight = 0;
366
367    while ((packet_out = TAILQ_FIRST(&mc->mc_packets_out)))
368    {
369        TAILQ_REMOVE(&mc->mc_packets_out, packet_out, po_next);
370        if (packet_out->po_flags & PO_SENT)
371            in_flight |= MCONN_PACKET_MASK(packet_out->po_packno);
372        mini_destroy_packet(mc, packet_out);
373    }
374
375    return in_flight;
376}
377
378
379static unsigned
380process_connection_close_frame (struct mini_conn *mc,
381        lsquic_packet_in_t *packet_in, const unsigned char *p, size_t len)
382{
383    uint64_t error_code;
384    uint16_t reason_len;
385    uint8_t reason_off;
386    int parsed_len;
387
388    (void) drop_packets_out(mc);
389    parsed_len = mc->mc_conn.cn_pf->pf_parse_connect_close_frame(p, len,
390                            NULL, &error_code, &reason_len, &reason_off);
391    if (parsed_len < 0)
392        return 0;
393    mc->mc_error_code = (uint64_t) error_code;
394    EV_LOG_CONNECTION_CLOSE_FRAME_IN(LSQUIC_LOG_CONN_ID, error_code,
395                            (int) reason_len, (const char *) p + reason_off);
396    if (error_code != 25        /* No recent network activity */
397        && error_code != 62     /* An active session exists for the given IP */
398        && error_code != 27 )   /* Write failed with error: -142 (Unknown error)*/
399    {
400        LSQ_WARN("Received CONNECTION_CLOSE frame (code: %"PRIu64"; reason: %.*s)",
401                 error_code, (int) reason_len, (const char *) p + reason_off);
402    }
403    MCHIST_APPEND(mc, MCHE_CONN_CLOSE);
404    return 0;   /* This shuts down the connection */
405}
406
407
408static unsigned
409process_goaway_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
410                                        const unsigned char *p, size_t len)
411{
412    lsquic_stream_id_t stream_id;
413    uint32_t error_code;
414    uint16_t reason_length;
415    const char *reason;
416    int parsed_len;
417    parsed_len = mc->mc_conn.cn_pf->pf_parse_goaway_frame(p, len, &error_code, &stream_id,
418                                              &reason_length, &reason);
419    if (parsed_len < 0)
420        return 0;
421    EV_LOG_GOAWAY_FRAME_IN(LSQUIC_LOG_CONN_ID, error_code, stream_id,
422        reason_length, reason);
423    LSQ_DEBUG("received GOAWAY frame, last good stream ID: %"PRIu64", "
424        "error code: 0x%X, reason: `%.*s'", stream_id, error_code,
425        reason_length, reason);
426    if (stream_id != 0) /* This is odd.  We warn: */
427        LSQ_WARN("stream ID is %"PRIu64" in GOAWAY frame", stream_id);
428    mc->mc_conn.cn_flags |= LSCONN_PEER_GOING_AWAY;
429    return parsed_len;
430}
431
432
433static unsigned
434process_invalid_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
435                                        const unsigned char *p, size_t len)
436{
437    LSQ_INFO("invalid frame");
438    MCHIST_APPEND(mc, MCHE_INVALID_FRAME);
439    return 0;
440}
441
442
443static unsigned
444count_zero_bytes (const unsigned char *p, size_t len)
445{
446    const unsigned char *const end = p + len;
447    while (p < end && 0 == *p)
448        ++p;
449    return len - (end - p);
450}
451
452
453static unsigned
454process_padding_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
455                                        const unsigned char *p, size_t len)
456{
457    len = (size_t) count_zero_bytes(p, len);
458    EV_LOG_PADDING_FRAME_IN(LSQUIC_LOG_CONN_ID, len);
459    return len;
460}
461
462
463static unsigned
464process_ping_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
465                                        const unsigned char *p, size_t len)
466{
467    EV_LOG_PING_FRAME_IN(LSQUIC_LOG_CONN_ID);
468    return 1;
469}
470
471
472static unsigned
473process_rst_stream_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
474                                            const unsigned char *p, size_t len)
475{
476    lsquic_stream_id_t stream_id;
477    uint64_t offset, error_code;
478    int parsed_len;
479    parsed_len = mc->mc_conn.cn_pf->pf_parse_rst_frame(p, len, &stream_id, &offset, &error_code);
480    if (parsed_len < 0)
481        return 0;
482    EV_LOG_RST_STREAM_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_id, offset,
483                                                                error_code);
484    LSQ_DEBUG("Got RST_STREAM; stream: %"PRIu64"; offset: 0x%"PRIX64, stream_id,
485                                                                    offset);
486    if (is_handshake_stream_id(mc, stream_id))
487    {
488        LSQ_INFO("handshake stream reset, closing connection");
489        return 0;
490    }
491    else
492        return parsed_len;
493}
494
495
496static unsigned
497process_stop_waiting_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
498                                             const unsigned char *p, size_t len)
499{
500    lsquic_packno_t least;
501    enum packno_bits bits = lsquic_packet_in_packno_bits(packet_in);
502    int parsed_len;
503    parsed_len = mc->mc_conn.cn_pf->pf_parse_stop_waiting_frame(p, len, packet_in->pi_packno, bits,
504                                                                        &least);
505    if (parsed_len < 0)
506        return 0;
507    EV_LOG_STOP_WAITING_FRAME_IN(LSQUIC_LOG_CONN_ID, least);
508    LSQ_DEBUG("Got STOP_WAITING frame, least unacked: %"PRIu64, least);
509    if (least > MINICONN_MAX_PACKETS)
510        return 0;
511    else
512    {
513        mc->mc_cutoff = least;
514        return parsed_len;
515    }
516}
517
518
519static unsigned
520process_stream_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
521                                          const unsigned char *p, size_t len)
522{
523    stream_frame_t stream_frame;
524    int parsed_len;
525    parsed_len = mc->mc_conn.cn_pf->pf_parse_stream_frame(p, len, &stream_frame);
526    if (parsed_len < 0)
527        return 0;
528    EV_LOG_STREAM_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame);
529    LSQ_DEBUG("Got stream frame for stream #%"PRIu64, stream_frame.stream_id);
530    if (is_handshake_stream_id(mc, stream_frame.stream_id))
531    {
532        if (packet_in->pi_flags & PI_HSK_STREAM)
533        {   /* This is not supported for simplicity.  The spec recommends
534             * not putting more than one stream frame from the same stream
535             * into a single packet.  If this changes and clients actually
536             * do that, we can revisit this code.
537             */
538            LSQ_INFO("two handshake stream frames in single incoming packet");
539            MCHIST_APPEND(mc, MCHE_2HSK_1STREAM);
540            return 0;
541        }
542        if (stream_frame.data_frame.df_offset >= mc->mc_read_off)
543        {
544            packet_in->pi_flags |= PI_HSK_STREAM;
545            packet_in->pi_hsk_stream = p - packet_in->pi_data;
546            mc->mc_flags |= MC_HAVE_NEW_HSK;
547            MCHIST_APPEND(mc, MCHE_NEW_HSK);
548            if (0 == stream_frame.data_frame.df_offset)
549                /* First CHLO message: update maximum packet size */
550                mc->mc_path.np_pack_size = packet_in->pi_data_sz;
551        }
552        else
553        {
554            LSQ_DEBUG("drop duplicate frame");
555            MCHIST_APPEND(mc, MCHE_DUP_HSK);
556        }
557    }
558    return parsed_len;
559}
560
561
562static unsigned
563process_crypto_frame (struct mini_conn *mc, struct lsquic_packet_in *packet_in,
564                                          const unsigned char *p, size_t len)
565{
566    stream_frame_t stream_frame;
567    int parsed_len;
568    parsed_len = mc->mc_conn.cn_pf->pf_parse_crypto_frame(p, len,
569                                                                &stream_frame);
570    if (parsed_len < 0)
571        return 0;
572    EV_LOG_CRYPTO_FRAME_IN(LSQUIC_LOG_CONN_ID, &stream_frame,
573                                        lsquic_packet_in_enc_level(packet_in));
574    LSQ_DEBUG("Got CRYPTO frame at encryption level %s",
575                    lsquic_enclev2str[lsquic_packet_in_enc_level(packet_in)]);
576    if (packet_in->pi_flags & PI_HSK_STREAM)
577    {   /* This is not supported for simplicity: assume a single CRYPTO frame
578         * per packet.  If this changes, we can revisit this code.
579         */
580        LSQ_INFO("two handshake stream frames in single incoming packet");
581        MCHIST_APPEND(mc, MCHE_2HSK_1STREAM);
582        return 0;
583    }
584    if (stream_frame.data_frame.df_offset >= mc->mc_read_off)
585    {
586        packet_in->pi_flags |= PI_HSK_STREAM;
587        packet_in->pi_hsk_stream = p - packet_in->pi_data;
588        mc->mc_flags |= MC_HAVE_NEW_HSK;
589        MCHIST_APPEND(mc, MCHE_NEW_HSK);
590        if (0 == stream_frame.data_frame.df_offset)
591            /* First CHLO message: update maximum packet size */
592            mc->mc_path.np_pack_size = packet_in->pi_data_sz;
593    }
594    else
595    {
596        LSQ_DEBUG("drop duplicate frame");
597        MCHIST_APPEND(mc, MCHE_DUP_HSK);
598    }
599    return parsed_len;
600}
601
602
603static unsigned
604process_window_update_frame (struct mini_conn *mc,
605            lsquic_packet_in_t *packet_in, const unsigned char *p, size_t len)
606{
607    lsquic_stream_id_t stream_id;
608    uint64_t offset;
609    int parsed_len;
610    parsed_len = mc->mc_conn.cn_pf->pf_parse_window_update_frame(p, len, &stream_id, &offset);
611    if (parsed_len < 0)
612        return 0;
613    EV_LOG_WINDOW_UPDATE_FRAME_IN(LSQUIC_LOG_CONN_ID, stream_id, offset);
614    if (is_handshake_stream_id(mc, stream_id))
615        /* This should not happen: why would the client send us WINDOW_UPDATE
616         * on stream 1?
617         */
618        LSQ_WARN("client sent WINDOW_UPDATE for handshake stream, "
619                                                    "offset %"PRIu64, offset);
620    return parsed_len;
621}
622
623
624typedef unsigned (*process_frame_f)(
625    struct mini_conn *, lsquic_packet_in_t *, const unsigned char *p, size_t);
626
627
628static process_frame_f const process_frames[N_QUIC_FRAMES] =
629{
630    [QUIC_FRAME_ACK]                  =  process_ack_frame,
631    [QUIC_FRAME_BLOCKED]              =  process_blocked_frame,
632    [QUIC_FRAME_CONNECTION_CLOSE]     =  process_connection_close_frame,
633    [QUIC_FRAME_CRYPTO]               =  process_crypto_frame,
634    [QUIC_FRAME_GOAWAY]               =  process_goaway_frame,
635    [QUIC_FRAME_INVALID]              =  process_invalid_frame,
636    [QUIC_FRAME_PADDING]              =  process_padding_frame,
637    [QUIC_FRAME_PING]                 =  process_ping_frame,
638    [QUIC_FRAME_RST_STREAM]           =  process_rst_stream_frame,
639    [QUIC_FRAME_STOP_WAITING]         =  process_stop_waiting_frame,
640    [QUIC_FRAME_STREAM]               =  process_stream_frame,
641    [QUIC_FRAME_WINDOW_UPDATE]        =  process_window_update_frame,
642};
643
644
645static unsigned
646process_packet_frame (struct mini_conn *mc, lsquic_packet_in_t *packet_in,
647                      const unsigned char *p, size_t len)
648{
649    enum quic_frame_type type = mc->mc_conn.cn_pf->pf_parse_frame_type(p[0]);
650    packet_in->pi_frame_types |= 1 << type;
651    return process_frames[type](mc, packet_in, p, len);
652}
653
654
655static void
656record_largest_recv (struct mini_conn *mc, lsquic_time_t t)
657{
658    if (t < mc->mc_created)
659    {
660        LSQ_WARN("largest received predates creation");
661        return;
662    }
663    t -= mc->mc_created;
664    mc->mc_largest_recv[0] = t;
665    mc->mc_largest_recv[1] = t >> 8;
666    mc->mc_largest_recv[2] = t >> 16;
667    LSQ_DEBUG("recorded largest received timestamp as %"PRIu64" usec since "
668                                                            "creation", t);
669}
670
671
672static enum dec_packin
673conn_decrypt_packet (struct mini_conn *conn, lsquic_packet_in_t *packet_in)
674{
675    return conn->mc_conn.cn_esf_c->esf_decrypt_packet(
676                        conn->mc_conn.cn_enc_session, conn->mc_enpub,
677                        &conn->mc_conn, packet_in);
678}
679
680
681/* PRP: Process Regular Packet */
682enum proc_rp { PRP_KEEP, PRP_DEFER, PRP_DROP, PRP_ERROR, };
683
684
685static enum proc_rp
686conn_decrypt_packet_or (struct mini_conn *mc,
687                                        struct lsquic_packet_in *packet_in)
688{
689    if (DECPI_OK == conn_decrypt_packet(mc, packet_in))
690    {
691        MCHIST_APPEND(mc, MCHE_DECRYPTED);
692        return PRP_KEEP;
693    }
694    else if (mc->mc_conn.cn_esf.g->esf_have_key_gt_one(
695                                            mc->mc_conn.cn_enc_session))
696    {
697        LSQ_INFO("could not decrypt packet: drop");
698        mc->mc_dropped_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
699        MCHIST_APPEND(mc, MCHE_UNDECR_DROP);
700        return PRP_DROP;
701    }
702    else if ((packet_in->pi_flags & PI_OWN_DATA) ||
703            0 == lsquic_conn_copy_and_release_pi_data(&mc->mc_conn,
704                                                mc->mc_enpub, packet_in))
705    {
706        assert(packet_in->pi_flags & PI_OWN_DATA);
707        LSQ_INFO("could not decrypt packet: defer");
708        mc->mc_deferred_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
709        MCHIST_APPEND(mc, MCHE_UNDECR_DEFER);
710        return PRP_DEFER;
711    }
712    else
713    {
714        MCHIST_APPEND(mc, MCHE_ENOMEM);
715        return PRP_ERROR;   /* Memory allocation must have failed */
716    }
717}
718
719
720static enum proc_rp
721process_regular_packet (struct mini_conn *mc, lsquic_packet_in_t *packet_in)
722{
723    const unsigned char *p, *pend;
724    enum proc_rp prp;
725    unsigned len;
726
727    /* Decrypt packet if necessary */
728    if (0 == (packet_in->pi_flags & PI_DECRYPTED))
729    {
730        prp = conn_decrypt_packet_or(mc, packet_in);
731        if (prp != PRP_KEEP)
732            return prp;
733    }
734
735    /* Update receive history before processing the packet: if there is an
736     * error, the connection is terminated and recording this packet number
737     * is helpful when it is printed along with other diagnostics in dtor.
738     */
739    if (0 == mc->mc_received_packnos ||
740            packet_in->pi_packno > highest_bit_set(mc->mc_received_packnos) + 1)
741        record_largest_recv(mc, packet_in->pi_received);
742    mc->mc_received_packnos |= MCONN_PACKET_MASK(packet_in->pi_packno);
743
744    /* Parse and process frames */
745    p = packet_in->pi_data + packet_in->pi_header_sz;
746    pend = packet_in->pi_data + packet_in->pi_data_sz;
747    while (p < pend)
748    {
749        len = process_packet_frame(mc, packet_in, p, pend - p);
750        if (len > 0)
751            p += len;
752        else
753        {
754            if (mc->mc_conn.cn_pf->pf_parse_frame_type(p[0]) !=
755                                                    QUIC_FRAME_CONNECTION_CLOSE)
756                LSQ_WARN("error parsing frame: packno %"PRIu64"; sz: %u; type: "
757                    "0x%X", packet_in->pi_packno, packet_in->pi_data_sz, p[0]);
758            MCHIST_APPEND(mc, MCHE_EFRAME);
759            return PRP_ERROR;
760        }
761    }
762
763    mc->mc_flags |= MC_GEN_ACK;
764
765    return PRP_KEEP;
766}
767
768
769struct hsk_chunk
770{
771    lsquic_packet_in_t  *hsk_packet_in;
772    const unsigned char *hsk_data;
773    unsigned             hsk_off;
774    unsigned             hsk_sz;
775};
776
777
778static int
779compare_hsk_chunks (const void *ap, const void *bp)
780{
781    const struct hsk_chunk *a = ap;
782    const struct hsk_chunk *b = bp;
783    return (a->hsk_off > b->hsk_off) - (b->hsk_off > a->hsk_off);
784}
785
786
787struct mini_stream_ctx
788{
789    const unsigned char     *buf;
790    size_t                   bufsz;
791    size_t                   off;
792};
793
794
795static int
796mini_stream_has_data (const struct mini_stream_ctx *ms_ctx)
797{
798    return ms_ctx->off < ms_ctx->bufsz;
799}
800
801
802static size_t
803mini_stream_read (void *stream, void *buf, size_t len, int *reached_fin)
804{
805    struct mini_stream_ctx *ms_ctx = stream;
806    size_t avail = ms_ctx->bufsz - ms_ctx->off;
807    if (avail < len)
808        len = avail;
809    memcpy(buf, ms_ctx->buf + ms_ctx->off, len);
810    ms_ctx->off += len;
811    *reached_fin = 0;
812    return len;
813}
814
815
816/* Wrapper to throw out reached_fin */
817static size_t
818mini_stream_read_for_crypto (void *stream, void *buf, size_t len)
819{
820    size_t retval;
821    int reached_fin;
822
823    retval = mini_stream_read(stream, buf, len, &reached_fin);
824    return retval;
825}
826
827
828static size_t
829mini_stream_size (void *stream)
830{
831    struct mini_stream_ctx *ms_ctx = stream;
832    size_t avail = ms_ctx->bufsz - ms_ctx->off;
833    return avail;
834}
835
836
837static int
838mini_stream_fin (void *stream)
839{   /* There is never a FIN on the handshake stream */
840    return 0;
841}
842
843
844static lsquic_packno_t
845next_packno (struct mini_conn *mc)
846{
847    if (mc->mc_cur_packno < MINICONN_MAX_PACKETS)
848    {
849        return ++mc->mc_cur_packno;
850    }
851    else
852    {
853        if (!(mc->mc_flags & MC_OO_PACKNOS))
854        {
855            MCHIST_APPEND(mc, MCHE_OUT_OF_PACKNOS);
856            mc->mc_flags |= MC_OO_PACKNOS;
857            LSQ_DEBUG("ran out of outgoing packet numbers");
858        }
859        return MINICONN_MAX_PACKETS + 1;
860    }
861}
862
863
864static lsquic_packet_out_t *
865allocate_packet_out (struct mini_conn *mc, const unsigned char *nonce)
866{
867    lsquic_packet_out_t *packet_out;
868    lsquic_packno_t packno;
869    packno = next_packno(mc);
870    if (packno > MINICONN_MAX_PACKETS)
871    {
872        LSQ_DEBUG("ran out of outgoing packet numbers, won't allocate packet");
873        return NULL;
874    }
875    packet_out = lsquic_packet_out_new(&mc->mc_enpub->enp_mm, NULL, 1,
876                &mc->mc_conn, GQUIC_PACKNO_LEN_1, NULL, nonce, &mc->mc_path);
877    if (!packet_out)
878    {
879        LSQ_WARN("could not allocate packet: %s", strerror(errno));
880        return NULL;
881    }
882    packet_out->po_loss_chain = packet_out;
883    packet_out->po_packno = packno;
884    packet_out->po_flags |= PO_MINI;
885    if (mc->mc_flags & MC_HAVE_SHLO)
886    {
887        packet_out->po_flags |= PO_HELLO;
888        packet_out->po_header_type = HETY_0RTT;
889    }
890    if (mc->mc_conn.cn_version >= LSQVER_050)
891    {
892        if (nonce)
893            packet_out->po_header_type = HETY_0RTT;
894        else
895            packet_out->po_header_type = HETY_INITIAL;
896    }
897    lsquic_packet_out_set_pns(packet_out, PNS_APP);
898    TAILQ_INSERT_TAIL(&mc->mc_packets_out, packet_out, po_next);
899    LSQ_DEBUG("allocated packet #%"PRIu64", nonce: %d", packno, !!nonce);
900    MCHIST_APPEND(mc, MCHE_NEW_PACKET_OUT);
901    EV_LOG_PACKET_CREATED(LSQUIC_LOG_CONN_ID, packet_out);
902    return packet_out;
903}
904
905
906static struct lsquic_packet_out *
907to_packet_pre_Q050 (struct mini_conn *mc, struct mini_stream_ctx *ms_ctx,
908                    const unsigned char *nonce)
909{
910    struct lsquic_packet_out *packet_out;
911    size_t cur_off;
912    int len;
913
914    packet_out = allocate_packet_out(mc, nonce);
915    if (!packet_out)
916        return NULL;
917    cur_off = ms_ctx->off;
918    len = mc->mc_conn.cn_pf->pf_gen_stream_frame(
919            packet_out->po_data + packet_out->po_data_sz,
920            lsquic_packet_out_avail(packet_out),
921            1, mc->mc_write_off, mini_stream_fin(ms_ctx),
922            mini_stream_size(ms_ctx), mini_stream_read, ms_ctx);
923    if (len < 0)
924    {
925        LSQ_WARN("cannot generate STREAM frame (avail: %u)",
926                                    lsquic_packet_out_avail(packet_out));
927        return NULL;
928    }
929    mc->mc_write_off += ms_ctx->off - cur_off;
930    EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, mc->mc_conn.cn_pf,
931                        packet_out->po_data + packet_out->po_data_sz, len);
932    packet_out->po_data_sz += len;
933    packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
934    if (0 == lsquic_packet_out_avail(packet_out))
935        packet_out->po_flags |= PO_STREAM_END;
936
937    return packet_out;
938}
939
940
941static struct lsquic_packet_out *
942to_packet_Q050plus (struct mini_conn *mc, struct mini_stream_ctx *ms_ctx,
943                    const unsigned char *nonce)
944{
945    struct lsquic_packet_out *packet_out;
946    size_t cur_off;
947    int len;
948
949    if (nonce && !(mc->mc_flags & MC_WR_OFF_RESET))
950    {
951        mc->mc_write_off = 0;
952        mc->mc_flags |= MC_WR_OFF_RESET;
953    }
954
955    packet_out = allocate_packet_out(mc, nonce);
956    if (!packet_out)
957        return NULL;
958    cur_off = ms_ctx->off;
959    len = mc->mc_conn.cn_pf->pf_gen_crypto_frame(
960            packet_out->po_data + packet_out->po_data_sz,
961            lsquic_packet_out_avail(packet_out), mc->mc_write_off,
962            mini_stream_size(ms_ctx), mini_stream_read_for_crypto, ms_ctx);
963    if (len < 0)
964    {
965        LSQ_WARN("cannot generate CRYPTO frame (avail: %u)",
966                                    lsquic_packet_out_avail(packet_out));
967        return NULL;
968    }
969    mc->mc_write_off += ms_ctx->off - cur_off;
970    EV_LOG_GENERATED_CRYPTO_FRAME(LSQUIC_LOG_CONN_ID, mc->mc_conn.cn_pf,
971                        packet_out->po_data + packet_out->po_data_sz, len);
972    packet_out->po_data_sz += len;
973    packet_out->po_frame_types |= 1 << QUIC_FRAME_CRYPTO;
974
975    return packet_out;
976}
977
978
979static int
980packetize_response (struct mini_conn *mc, const unsigned char *buf,
981                    size_t bufsz, const unsigned char *nonce)
982{
983    struct mini_stream_ctx ms_ctx;
984    lsquic_packet_out_t *packet_out;
985    struct lsquic_packet_out * (*const to_packet) (struct mini_conn *,
986                struct mini_stream_ctx *, const unsigned char *)
987        = mc->mc_conn.cn_version < LSQVER_050
988            ? to_packet_pre_Q050 : to_packet_Q050plus;
989
990    LSQ_DEBUG("Packetizing %zd bytes of handshake response", bufsz);
991
992    ms_ctx.buf   = buf;
993    ms_ctx.bufsz = bufsz;
994    ms_ctx.off   = 0;
995
996    do
997    {
998        packet_out = to_packet(mc, &ms_ctx, nonce);
999        if (!packet_out)
1000            return -1;
1001    }
1002    while (mini_stream_has_data(&ms_ctx));
1003
1004    /* PAD the last packet with NULs.  ACK and STOP_WAITING go into a separate
1005     * packet.
1006     */
1007    if (lsquic_packet_out_avail(packet_out))
1008    {
1009        EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "generated PADDING frame %u "
1010                            "bytes long", lsquic_packet_out_avail(packet_out));
1011        memset(packet_out->po_data + packet_out->po_data_sz, 0,
1012                                        lsquic_packet_out_avail(packet_out));
1013        packet_out->po_data_sz += lsquic_packet_out_avail(packet_out);
1014        packet_out->po_frame_types |= 1 << QUIC_FRAME_PADDING;
1015    }
1016
1017    return 0;
1018}
1019
1020
1021static int
1022continue_handshake (struct mini_conn *mc)
1023{
1024    lsquic_packet_in_t *packet_in;
1025    unsigned n_hsk_chunks = 0, n_contig, n, bufsz, off;
1026    int s, rv;
1027    size_t out_len;
1028    enum handshake_error he;
1029    unsigned char *buf_in_16k, *buf_out;
1030    const unsigned char *buf_in;
1031    time_t t;
1032    stream_frame_t frame;
1033    struct hsk_chunk hsk_chunks[MINICONN_MAX_PACKETS], *hsk_chunk;
1034    unsigned char nonce_buf[32];
1035    int nonce_set = 0;
1036    int (*parse_frame)(const unsigned char *, size_t, struct stream_frame *)
1037        = mc->mc_conn.cn_version < LSQVER_050
1038            ? mc->mc_conn.cn_pf->pf_parse_stream_frame
1039            : mc->mc_conn.cn_pf->pf_parse_crypto_frame;
1040
1041    /* Get handshake stream data from each packet that contains a handshake
1042     * stream frame and place them into `hsk_chunks' array.
1043     */
1044    TAILQ_FOREACH(packet_in, &mc->mc_packets_in, pi_next)
1045    {
1046        assert(n_hsk_chunks < sizeof(hsk_chunks) / sizeof(hsk_chunks[0]));
1047        if (0 == (packet_in->pi_flags & PI_HSK_STREAM))
1048            continue;
1049        s = parse_frame(packet_in->pi_data + packet_in->pi_hsk_stream,
1050                packet_in->pi_data_sz - packet_in->pi_hsk_stream, &frame);
1051        if (-1 == s)
1052        {
1053            LSQ_WARN("cannot process hsk stream frame in packet %"PRIu64,
1054                packet_in->pi_packno);
1055            return -1;
1056        }
1057        hsk_chunk = &hsk_chunks[ n_hsk_chunks++ ];
1058        hsk_chunk->hsk_packet_in = packet_in;
1059        hsk_chunk->hsk_data      = frame.data_frame.df_data;
1060        hsk_chunk->hsk_off       = frame.data_frame.df_offset;
1061        hsk_chunk->hsk_sz        = frame.data_frame.df_size;
1062    }
1063    assert(n_hsk_chunks > 0);
1064
1065    if (n_hsk_chunks > 1)
1066    {
1067        /* Sort handshake stream data */
1068        qsort(hsk_chunks, n_hsk_chunks, sizeof(hsk_chunks[0]),
1069                                                        compare_hsk_chunks);
1070        /* Figure out how many packets contain handshake stream data in a
1071         * contiguous buffer and how large this data is.
1072         */
1073        for (n = 1, n_contig = 1, bufsz = hsk_chunks[0].hsk_sz;
1074                                                        n < n_hsk_chunks; ++n)
1075            if (hsk_chunks[n - 1].hsk_off + hsk_chunks[n - 1].hsk_sz ==
1076                                                        hsk_chunks[n].hsk_off)
1077            {
1078                ++n_contig;
1079                bufsz += hsk_chunks[n].hsk_sz;
1080            }
1081            else
1082                break;
1083    }
1084    else
1085    {
1086        n_contig = 1;
1087        bufsz = hsk_chunks[0].hsk_sz;
1088    }
1089
1090    /* Handshake handler expects to start reading at a particular offset.
1091     */
1092    if (hsk_chunks[0].hsk_off != mc->mc_read_off)
1093    {
1094        LSQ_DEBUG("smallest hsk offset is %u, need %hu",
1095                                hsk_chunks[0].hsk_off, mc->mc_read_off);
1096        MCHIST_APPEND(mc, MCHE_HELLO_HOLE);
1097        return 0;
1098    }
1099
1100    LSQ_DEBUG("# of contiguous stream frames: %u out of %u; offset: %u; "
1101        "total size: %u", n_contig, n_hsk_chunks, hsk_chunks[0].hsk_off, bufsz);
1102
1103    if (bufsz > 16 * 1024)
1104    {
1105        LSQ_INFO("too much contiguous handshake data (%u bytes); max: %u",
1106            bufsz, 16 * 1024);
1107        MCHIST_APPEND(mc, MCHE_HELLO_TOO_MUCH);
1108        return -1;
1109    }
1110
1111    /* From here on, since we need to clean up, we use `rv' and `goto end'
1112     * to handle error conditions and cleanup.
1113     */
1114    rv = -1;
1115    if (n_contig > 1)
1116    {
1117        buf_in = buf_in_16k = lsquic_mm_get_16k(&mc->mc_enpub->enp_mm);
1118        if (!buf_in)
1119        {
1120            LSQ_WARN("could not allocate in buffer: %s", strerror(errno));
1121            buf_out = NULL;
1122            goto end;
1123        }
1124        /* Create a single contiguous buffer to pass to lsquic_enc_session_handle_chlo */
1125        off = 0;
1126        for (n = 0; n < n_contig; ++n)
1127        {
1128            memcpy(buf_in_16k + off, hsk_chunks[n].hsk_data,
1129                                                    hsk_chunks[n].hsk_sz);
1130            off += hsk_chunks[n].hsk_sz;
1131        }
1132        assert(off == bufsz);
1133    }
1134    else
1135    {
1136        buf_in_16k = NULL;
1137        buf_in = hsk_chunks[0].hsk_data;
1138    }
1139
1140    buf_out = lsquic_mm_get_16k(&mc->mc_enpub->enp_mm);
1141    if (!buf_out)
1142    {
1143        LSQ_WARN("could not allocate out buffer: %s", strerror(errno));
1144        goto end;
1145    }
1146    out_len = 16 * 1024;
1147
1148    /* Allocate enc_session for the server if first time around: */
1149    if (!mc->mc_conn.cn_enc_session)
1150    {
1151        mc->mc_conn.cn_enc_session =
1152            mc->mc_conn.cn_esf.g->esf_create_server(&mc->mc_conn,
1153                                        mc->mc_conn.cn_cid, mc->mc_enpub);
1154        if (!mc->mc_conn.cn_enc_session)
1155        {
1156            LSQ_WARN("cannot create new enc session");
1157            goto end;
1158        }
1159        MCHIST_APPEND(mc, MCHE_NEW_ENC_SESS);
1160    }
1161
1162    t = time(NULL);
1163    he = mc->mc_conn.cn_esf.g->esf_handle_chlo(mc->mc_conn.cn_enc_session,
1164            mc->mc_conn.cn_version,
1165            buf_in, bufsz, t, NP_PEER_SA(&mc->mc_path),
1166            NP_LOCAL_SA(&mc->mc_path),
1167            buf_out, &out_len, nonce_buf, &nonce_set);
1168
1169    if (HS_SHLO == he)
1170        mc->mc_flags |=  MC_HAVE_SHLO;
1171    else
1172        mc->mc_flags &= ~MC_HAVE_SHLO;
1173
1174    MCHIST_APPEND(mc, he == DATA_NOT_ENOUGH ? MCHE_HANDLE_NOT_ENOUGH :
1175                      he == HS_SHLO         ? MCHE_HANDLE_SHLO :
1176                      he == HS_1RTT         ? MCHE_HANDLE_1RTT :
1177                      he == HS_2RTT         ? MCHE_HANDLE_2RTT :
1178                      he == HS_ERROR        ? MCHE_HANDLE_ERROR :
1179                                              MCHE_HAHDLE_UNKNOWN);
1180
1181    if ((HS_SHLO == he || HS_1RTT == he) && !mc->mc_rtt_stats.srtt)
1182    {
1183        uint32_t irtt;
1184        if (0 == mc->mc_conn.cn_esf.g->esf_get_peer_setting(
1185                        mc->mc_conn.cn_enc_session, QTAG_IRTT, &irtt))
1186        {
1187            /* Do not allow the client to specify unreasonable values:
1188             * smaller than 10ms or larger than 15s.  Per reference
1189             * implementation.
1190             */
1191            if (irtt > 15 * 1000 * 1000)
1192                irtt = 15 * 1000 * 1000;
1193            else if (irtt < 10 * 1000)
1194                irtt = 10 * 1000;
1195            lsquic_rtt_stats_update(&mc->mc_rtt_stats, irtt, 0);
1196            LSQ_DEBUG("Set initial SRTT to %"PRIu32" usec based on client-"
1197                "supplied IRTT value", irtt);
1198        }
1199    }
1200
1201    switch (he)
1202    {
1203    case DATA_NOT_ENOUGH:
1204        LSQ_DEBUG("lsquic_enc_session_handle_chlo needs more data");
1205        break;
1206    case HS_SHLO:
1207        mc->mc_conn.cn_flags |= LSCONN_HANDSHAKE_DONE;
1208        mc->mc_flags |= MC_PROMOTE;
1209        LSQ_DEBUG("lsquic_enc_session_handle_chlo returned %d, promote", he);
1210        /* Fall through */
1211    case HS_1RTT:
1212        assert(out_len > 0);
1213        if (mc->mc_conn.cn_version < LSQVER_046
1214                    && !mc->mc_conn.cn_esf.g->esf_get_peer_option(
1215                                    mc->mc_conn.cn_enc_session, QTAG_NSTP))
1216            mc->mc_flags |= MC_STOP_WAIT_ON;
1217        if (0 != packetize_response(mc, buf_out, out_len,
1218                                            nonce_set ? nonce_buf : NULL))
1219            goto end;
1220        mc->mc_read_off += bufsz;
1221        for (n = 0; n < n_contig; ++n)
1222            hsk_chunks[n].hsk_packet_in->pi_flags &= ~PI_HSK_STREAM;
1223        LSQ_DEBUG("read offset is now %hu", mc->mc_read_off);
1224        break;
1225    default:
1226        LSQ_WARN("unexpected return value from lsquic_enc_session_handle_chlo: %u", he);
1227        /* fallthru */
1228    case HS_ERROR:
1229#if !LSQUIC_KEEP_ENC_SESS_HISTORY
1230        mc->mc_conn.cn_esf.g->esf_destroy(mc->mc_conn.cn_enc_session);
1231        mc->mc_conn.cn_enc_session = NULL;
1232#endif
1233        mc->mc_flags |= MC_HSK_ERR;
1234        LSQ_INFO("lsquic_enc_session_handle_chlo returned an error (%d)", he);
1235        goto end;
1236    }
1237
1238    rv = 0;
1239
1240  end:
1241    mc->mc_flags &= ~MC_HAVE_SHLO;
1242    if (buf_in_16k)
1243        lsquic_mm_put_16k(&mc->mc_enpub->enp_mm, buf_in_16k);
1244    if (buf_out)
1245        lsquic_mm_put_16k(&mc->mc_enpub->enp_mm, buf_out);
1246    return rv;
1247}
1248
1249
1250struct mini_rechist
1251{
1252    const struct mini_conn     *mc;
1253    mconn_packno_set_t          cur_set;
1254    int                         cur_idx;
1255    struct lsquic_packno_range  range;   /* We return a pointer to this */
1256};
1257
1258
1259static void
1260mini_rechist_init (struct mini_rechist *rechist, const struct mini_conn *mc)
1261{
1262    rechist->mc      = mc;
1263    rechist->cur_set = 0;
1264    rechist->cur_idx = 0;
1265}
1266
1267
1268static lsquic_time_t
1269mini_rechist_largest_recv (void *rechist_ctx)
1270{
1271    struct mini_rechist *rechist = rechist_ctx;
1272    const struct mini_conn *mc = rechist->mc;
1273    lsquic_time_t delta =  mc->mc_largest_recv[0]
1274                        + (mc->mc_largest_recv[1] << 8)
1275                        + (mc->mc_largest_recv[2] << 16);
1276    LSQ_DEBUG("%s: largest received: %"PRIu64" usec since creation",
1277                                                            __func__, delta);
1278    return mc->mc_created + delta;
1279}
1280
1281
1282static const struct lsquic_packno_range *
1283mini_rechist_next (void *rechist_ctx)
1284{
1285    struct mini_rechist *rechist = rechist_ctx;
1286    const struct mini_conn *mc = rechist->mc;
1287    mconn_packno_set_t packnos;
1288    int i;
1289
1290    packnos = rechist->cur_set;
1291    if (0 == packnos)
1292        return NULL;
1293
1294    /* There may be a faster way to do this, but for now, we just want
1295     * correctness.
1296     */
1297    for (i = rechist->cur_idx; i >= 0; --i)
1298        if (packnos & (1ULL << i))
1299        {
1300            rechist->range.low  = i + 1;
1301            rechist->range.high = i + 1;
1302            break;
1303        }
1304    assert(i >= 0); /* We must have hit at least one bit */
1305    --i;
1306    for ( ; i >= 0 && (packnos & (1ULL << i)); --i)
1307        rechist->range.low = i + 1;
1308    if (i >= 0)
1309    {
1310        rechist->cur_set = packnos & ((1ULL << i) - 1);
1311        rechist->cur_idx = i;
1312    }
1313    else
1314        rechist->cur_set = 0;
1315    LSQ_DEBUG("%s: return [%"PRIu64", %"PRIu64"]", __func__,
1316                                rechist->range.low, rechist->range.high);
1317    return &rechist->range;
1318}
1319
1320
1321static const struct lsquic_packno_range *
1322mini_rechist_first (void *rechist_ctx)
1323{
1324    struct mini_rechist *rechist = rechist_ctx;
1325    rechist->cur_set = rechist->mc->mc_received_packnos;
1326    rechist->cur_idx = highest_bit_set(rechist->cur_set);
1327    return mini_rechist_next(rechist_ctx);
1328}
1329
1330
1331static lsquic_packno_t
1332least_unacked (const struct mini_conn *mc)
1333{
1334    mconn_packno_set_t unacked;
1335    lsquic_packno_t packno;
1336    unacked = mc->mc_sent_packnos & ~mc->mc_acked_packnos;
1337    if (unacked)
1338        packno = lowest_bit_set(unacked) + 1;
1339    else
1340        packno = highest_bit_set(mc->mc_sent_packnos) + 2;
1341    LSQ_DEBUG("%s: least unacked: %"PRIu64, __func__, packno);
1342    return packno;
1343}
1344
1345
1346static int
1347generate_ack_and_stop_waiting (struct mini_conn *mc, lsquic_time_t now)
1348{
1349    lsquic_packet_out_t *packet_out;
1350    struct mini_rechist rechist;
1351    int len, not_used_has_missing;
1352    lsquic_packno_t lunack;
1353
1354    /* Chrome's quic_server places ACK and STOP_WAITING frames into a separate
1355     * packet.
1356     */
1357    packet_out = allocate_packet_out(mc, NULL);
1358    if (!packet_out)
1359        return -1;
1360
1361    /* Generate ACK frame */
1362    mini_rechist_init(&rechist, mc);
1363    len = mc->mc_conn.cn_pf->pf_gen_ack_frame(packet_out->po_data + packet_out->po_data_sz,
1364                lsquic_packet_out_avail(packet_out), mini_rechist_first,
1365                mini_rechist_next, mini_rechist_largest_recv, &rechist,
1366                now, &not_used_has_missing, &packet_out->po_ack2ed, NULL);
1367    if (len < 0)
1368    {
1369        LSQ_WARN("could not generate ACK frame");
1370        return -1;
1371    }
1372    EV_LOG_GENERATED_ACK_FRAME(LSQUIC_LOG_CONN_ID, mc->mc_conn.cn_pf,
1373                        packet_out->po_data + packet_out->po_data_sz, len);
1374    packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
1375    packet_out->po_data_sz += len;
1376    packet_out->po_regen_sz += len;
1377    LSQ_DEBUG("wrote ACK frame of size %d", len);
1378
1379    /* Generate STOP_WAITING frame */
1380    if ((mc->mc_flags & MC_STOP_WAIT_ON) && mc->mc_sent_packnos)
1381    {
1382        lunack = least_unacked(mc);
1383        len = mc->mc_conn.cn_pf->pf_gen_stop_waiting_frame(packet_out->po_data +
1384                                                packet_out->po_data_sz,
1385                lsquic_packet_out_avail(packet_out), packet_out->po_packno,
1386                lsquic_packet_out_packno_bits(packet_out), lunack);
1387        if (len < 0)
1388        {
1389            LSQ_WARN("could not generate STOP_WAITING frame");
1390            return -1;
1391        }
1392        packet_out->po_data_sz += len;
1393        packet_out->po_regen_sz += len;
1394        packet_out->po_frame_types |= 1 << QUIC_FRAME_STOP_WAITING;
1395        LSQ_DEBUG("wrote STOP_WAITING frame of size %d", len);
1396        EV_LOG_GENERATED_STOP_WAITING_FRAME(LSQUIC_LOG_CONN_ID, lunack);
1397    }
1398    else if (mc->mc_flags & MC_STOP_WAIT_ON)
1399        LSQ_DEBUG("nothing sent: no need to generate STOP_WAITING frame");
1400
1401    mc->mc_flags |= MC_UNSENT_ACK;
1402    return 0;
1403}
1404
1405
1406static int
1407calc_retx_timeout (const struct mini_conn *mc)
1408{
1409    lsquic_time_t to;
1410    to = lsquic_rtt_stats_get_srtt(&mc->mc_rtt_stats);
1411    if (to)
1412    {
1413        to += to / 2;
1414        if (to < 10000)
1415            to = 10000;
1416    }
1417    else
1418        to = 300000;
1419    return to << mc->mc_hsk_count;
1420}
1421
1422
1423static void
1424return_enc_data (struct mini_conn *mc, struct lsquic_packet_out *packet_out)
1425{
1426    mc->mc_enpub->enp_pmi->pmi_return(mc->mc_enpub->enp_pmi_ctx,
1427        mc->mc_path.np_peer_ctx, packet_out->po_enc_data,
1428        lsquic_packet_out_ipv6(packet_out));
1429    packet_out->po_flags &= ~PO_ENCRYPTED;
1430    packet_out->po_enc_data = NULL;
1431}
1432
1433
1434static int
1435repackage_packet (struct mini_conn *mc, lsquic_packet_out_t *packet_out)
1436{
1437    const lsquic_packno_t oldno = packet_out->po_packno;
1438    const lsquic_packno_t packno = next_packno(mc);
1439    if (packno > MINICONN_MAX_PACKETS)
1440        return -1;
1441
1442    LSQ_DEBUG("Packet %"PRIu64" repackaged for resending as packet %"PRIu64,
1443                                                        oldno, packno);
1444    EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "packet %"PRIu64" repackaged for "
1445        "resending as packet %"PRIu64, oldno, packno);
1446    packet_out->po_packno = packno;
1447    packet_out->po_flags &= ~PO_SENT;
1448    if (packet_out->po_flags & PO_ENCRYPTED)
1449        return_enc_data(mc, packet_out);
1450    TAILQ_INSERT_TAIL(&mc->mc_packets_out, packet_out, po_next);
1451    return 0;
1452}
1453
1454
1455static int
1456handle_losses_and_have_unsent (struct mini_conn *mc, lsquic_time_t now)
1457{
1458    TAILQ_HEAD(, lsquic_packet_out) lost_packets =
1459                                    TAILQ_HEAD_INITIALIZER(lost_packets);
1460    lsquic_packet_out_t *packet_out, *next;
1461    lsquic_time_t retx_to = 0;
1462    unsigned n_to_send = 0;
1463
1464    for (packet_out = TAILQ_FIRST(&mc->mc_packets_out); packet_out;
1465                                                        packet_out = next)
1466    {
1467        next = TAILQ_NEXT(packet_out, po_next);
1468        if (packet_out->po_flags & PO_SENT)
1469        {
1470            if (0 == retx_to)
1471                retx_to = calc_retx_timeout(mc);
1472            if (packet_out->po_sent + retx_to < now)
1473            {
1474                LSQ_DEBUG("packet %"PRIu64" has been lost (rto: %"PRIu64")",
1475                                                packet_out->po_packno, retx_to);
1476                TAILQ_REMOVE(&mc->mc_packets_out, packet_out, po_next);
1477                TAILQ_INSERT_TAIL(&lost_packets, packet_out, po_next);
1478                mc->mc_lost_packnos |= MCONN_PACKET_MASK(packet_out->po_packno);
1479                MCHIST_APPEND(mc, MCHE_PACKET_LOST);
1480            }
1481        }
1482        else
1483            ++n_to_send;
1484    }
1485
1486    mc->mc_hsk_count += !TAILQ_EMPTY(&lost_packets);
1487
1488    while ((packet_out = TAILQ_FIRST(&lost_packets)))
1489    {
1490        TAILQ_REMOVE(&lost_packets, packet_out, po_next);
1491        if ((packet_out->po_frame_types & GQUIC_FRAME_RETRANSMITTABLE_MASK)
1492                                    && 0 == repackage_packet(mc, packet_out))
1493            ++n_to_send;
1494        else
1495            mini_destroy_packet(mc, packet_out);
1496    }
1497
1498    return n_to_send > 0;
1499}
1500
1501
1502static int
1503warning_is_warranted (const struct mini_conn *mc)
1504{
1505    return (mc->mc_flags & (MC_HSK_ERR|MC_OO_PACKNOS))
1506        || 0x1C /* QUIC_HANDSHAKE_FAILED                    */ == mc->mc_error_code
1507        || 0x1D /* QUIC_CRYPTO_TAGS_OUT_OF_ORDER            */ == mc->mc_error_code
1508        || 0x1E /* QUIC_CRYPTO_TOO_MANY_ENTRIES             */ == mc->mc_error_code
1509        || 0x1F /* QUIC_CRYPTO_INVALID_VALUE_LENGTH         */ == mc->mc_error_code
1510        || 0x21 /* QUIC_INVALID_CRYPTO_MESSAGE_TYPE         */ == mc->mc_error_code
1511        || 0x22 /* QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER    */ == mc->mc_error_code
1512        || 0x23 /* QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND  */ == mc->mc_error_code
1513        || 0x24 /* QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP */ == mc->mc_error_code
1514        || 0x29 /* QUIC_CRYPTO_TOO_MANY_REJECTS             */ == mc->mc_error_code
1515        || 0x2A /* QUIC_PROOF_INVALID                       */ == mc->mc_error_code
1516        || 0x2B /* QUIC_CRYPTO_DUPLICATE_TAG                */ == mc->mc_error_code
1517        || 0x2C /* QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT   */ == mc->mc_error_code
1518        || 0x2D /* QUIC_CRYPTO_SERVER_CONFIG_EXPIRED        */ == mc->mc_error_code
1519        || 0x35 /* QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED   */ == mc->mc_error_code
1520        ;
1521}
1522
1523
1524#if LSQUIC_KEEP_ENC_SESS_HISTORY
1525static void
1526maybe_log_enc_sess_history (const struct mini_conn *mc)
1527{
1528    char eshist[ESHIST_STR_SIZE];
1529    enum lsq_log_level log_level;
1530    const char *ua;
1531
1532    if (warning_is_warranted(mc))
1533        log_level = LSQ_LOG_WARN;
1534    else
1535        log_level = LSQ_LOG_DEBUG;
1536
1537    if (mc->mc_conn.cn_enc_session)
1538    {
1539        mc->mc_conn.cn_esf.g->esf_get_hist(mc->mc_conn.cn_enc_session, eshist);
1540        ua = mc->mc_conn.cn_esf.g->esf_get_ua(mc->mc_conn.cn_enc_session);
1541        LSQ_LOG1(log_level, "enc hist %s; User-Agent: %s", eshist,
1542                                                        ua ? ua : "<not set>");
1543    }
1544    else
1545        LSQ_LOG1(log_level, "enc session gone: no history to log");
1546}
1547
1548
1549#endif
1550
1551
1552
1553
1554static int
1555have_packets_to_send (struct mini_conn *mc, lsquic_time_t now)
1556{
1557    return handle_losses_and_have_unsent(mc, now);
1558}
1559
1560
1561static enum tick_st
1562mini_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
1563{
1564    struct mini_conn *mc = (struct mini_conn *) lconn;
1565    enum tick_st tick;
1566
1567    ++mc->mc_n_ticks;
1568
1569    if (mc->mc_created + mc->mc_enpub->enp_settings.es_handshake_to < now)
1570    {
1571        LSQ_DEBUG("connection expired: closing");
1572        tick = TICK_CLOSE;
1573        goto end;
1574    }
1575
1576    if (mc->mc_flags & MC_ERROR)
1577    {
1578        tick = TICK_CLOSE;
1579        goto end;
1580    }
1581
1582
1583    if ((mc->mc_flags & (MC_UNSENT_ACK|MC_GEN_ACK)) == MC_GEN_ACK)
1584    {
1585        if (0 != generate_ack_and_stop_waiting(mc, now))
1586        {
1587            mc->mc_flags |= MC_ERROR;
1588            tick = TICK_CLOSE;
1589            goto end;
1590        }
1591        else
1592            mc->mc_flags &= ~MC_GEN_ACK;
1593    }
1594
1595    if (have_packets_to_send(mc, now))
1596        tick = TICK_SEND;
1597    else
1598        tick = TICK_QUIET;
1599
1600    if (mc->mc_flags & MC_PROMOTE)
1601        tick |= TICK_PROMOTE;
1602
1603  end:
1604#if LSQUIC_KEEP_ENC_SESS_HISTORY
1605    if (tick & (TICK_CLOSE|TICK_PROMOTE))
1606        maybe_log_enc_sess_history(mc);
1607#endif
1608
1609    return tick;
1610}
1611
1612
1613static void
1614process_packet (struct mini_conn *mc, struct lsquic_packet_in *packet_in)
1615{
1616    switch (process_regular_packet(mc, packet_in))
1617    {
1618    case PRP_KEEP:
1619        assert(packet_in->pi_flags & PI_OWN_DATA);
1620        lsquic_packet_in_upref(packet_in);
1621        TAILQ_INSERT_TAIL(&mc->mc_packets_in, packet_in, pi_next);
1622        if (mc->mc_flags & MC_HAVE_NEW_HSK)
1623        {
1624            if (0 != continue_handshake(mc))
1625                mc->mc_flags |= MC_ERROR;
1626            mc->mc_flags &= ~MC_HAVE_NEW_HSK;
1627        }
1628        break;
1629    case PRP_DEFER:
1630        assert(packet_in->pi_flags & PI_OWN_DATA);
1631        lsquic_packet_in_upref(packet_in);
1632        if (mc->mc_n_deferred < MINI_CONN_MAX_DEFERRED)
1633        {
1634            TAILQ_INSERT_TAIL(&mc->mc_deferred, packet_in, pi_next);
1635            ++mc->mc_n_deferred;
1636        }
1637        else
1638            LSQ_DEBUG("won't defer more than %u packets: drop",
1639                                                MINI_CONN_MAX_DEFERRED);
1640        break;
1641    case PRP_ERROR:
1642        mc->mc_flags |= MC_ERROR;
1643        break;
1644    case PRP_DROP:
1645        break;
1646    }
1647}
1648
1649
1650/* Keep deferred list ordered by packet number, so that we can process all
1651 * of them in a single pass.
1652 */
1653static void
1654insert_into_deferred (struct mini_conn *mc, lsquic_packet_in_t *new_packet)
1655{
1656    lsquic_packet_in_t *packet_in;
1657
1658    lsquic_packet_in_upref(new_packet);
1659
1660    TAILQ_FOREACH(packet_in, &mc->mc_deferred, pi_next)
1661    if (packet_in->pi_packno > new_packet->pi_packno)
1662        break;
1663
1664    if (packet_in)
1665        TAILQ_INSERT_BEFORE(packet_in, new_packet, pi_next);
1666    else
1667        TAILQ_INSERT_TAIL(&mc->mc_deferred, new_packet, pi_next);
1668    ++mc->mc_n_deferred;
1669}
1670
1671
1672static void
1673process_deferred_packets (struct mini_conn *mc)
1674{
1675    lsquic_packet_in_t *last, *packet_in;
1676    int reached_last;
1677
1678    last = TAILQ_LAST(&mc->mc_deferred, head_packet_in);
1679    do
1680    {
1681        packet_in = TAILQ_FIRST(&mc->mc_deferred);
1682        TAILQ_REMOVE(&mc->mc_deferred, packet_in, pi_next);
1683        --mc->mc_n_deferred;
1684        process_packet(mc, packet_in);
1685        reached_last = packet_in == last;
1686        lsquic_packet_in_put(&mc->mc_enpub->enp_mm, packet_in);
1687    }
1688    while (!reached_last);
1689}
1690
1691
1692#if LSQUIC_RECORD_INORD_HIST
1693/* Packet number is encoded as a sequence of 1-bits and stored in mc_inord_hist
1694 * separated by 0 bits.  For example, sequence of packet numbers 3, 2, 1 would
1695 * be encoded as (starting with LSB) 1110110100000000...  This is not the most
1696 * space-efficient scheme, but it is simple to implement and should suffice for
1697 * our purposes.
1698 */
1699static void
1700record_inord_packno (struct mini_conn *mc, lsquic_packno_t packno)
1701{
1702    int n_avail;
1703    lsquic_packno_t mask;
1704
1705    for ( ; mc->mc_inord_idx < sizeof(mc->mc_inord_hist) /
1706                            sizeof(mc->mc_inord_hist[0]); ++mc->mc_inord_idx)
1707    {
1708        if (mc->mc_inord_hist[ mc->mc_inord_idx ])
1709            n_avail = __builtin_clzll(mc->mc_inord_hist[ mc->mc_inord_idx ]) - 1;
1710        else
1711            n_avail = sizeof(mc->mc_inord_hist[ mc->mc_inord_idx ]) * 8;
1712        if (n_avail >= (int) packno)
1713        {
1714            mask = (1ULL << (int) packno) - 1;
1715            mask <<= sizeof(mc->mc_inord_hist[ mc->mc_inord_idx ]) * 8 - n_avail;
1716            mc->mc_inord_hist[ mc->mc_inord_idx ] |= mask;
1717            return;                                             /* Success */
1718        }
1719    }
1720}
1721
1722
1723static void
1724inord_to_str (const struct mini_conn *mc, char *buf, size_t bufsz)
1725{
1726    unsigned long long hist;
1727    size_t off;
1728    ssize_t nw;
1729    unsigned n;
1730    int n_trail;
1731
1732    off = 0;
1733    for (n = 0; n < sizeof(mc->mc_inord_hist) /
1734                                        sizeof(mc->mc_inord_hist[0]); ++n)
1735    {
1736        hist = mc->mc_inord_hist[n];
1737        while (hist)
1738        {
1739            n_trail = __builtin_ctzll(~hist);
1740            nw = snprintf(buf + off, bufsz - off,
1741                /* No spaces are included on purpose: this makes it a single
1742                 * field and thus easy to process log using standard command-
1743                 * line tools, such as sork -k, for example.
1744                 */
1745                                        (off ? ",%d" : "%d"), n_trail);
1746            if ((size_t) nw > bufsz - off || nw < 0)
1747                break;
1748            off += nw;
1749            hist >>= n_trail + 1;
1750        }
1751    }
1752    buf[ bufsz - 1 ] = '\0';    /* CYA */
1753}
1754
1755
1756#endif
1757
1758
1759static void
1760mini_conn_ci_packet_in (struct lsquic_conn *lconn,
1761                        struct lsquic_packet_in *packet_in)
1762{
1763    struct mini_conn *mc = (struct mini_conn *) lconn;
1764
1765#if LSQUIC_RECORD_INORD_HIST
1766    record_inord_packno(mc, packet_in->pi_packno);
1767#endif
1768#if 0
1769    /* A convenient way to test lsquic_is_valid_hs_packet(): */
1770    if (!(mc->mc_sent_packnos))
1771        assert(lsquic_is_valid_hs_packet(NULL, packet_in->pi_data,
1772                                                    packet_in->pi_data_sz));
1773#endif
1774
1775    if (mc->mc_flags & MC_ERROR)
1776    {
1777        LSQ_DEBUG("error state: ignore packet %"PRIu64, packet_in->pi_packno);
1778        return;
1779    }
1780
1781    if (lsquic_packet_in_is_gquic_prst(packet_in))
1782    {
1783        LSQ_INFO("received reset packet");
1784        mc->mc_flags |= MC_ERROR;
1785        MCHIST_APPEND(mc, MCHE_PRST_IN);
1786        return;
1787    }
1788
1789    LSQ_DEBUG("packet in: %"PRIu64, packet_in->pi_packno);
1790    EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
1791
1792
1793    /* Check receive history */
1794    if (0 == packet_in->pi_packno)
1795    {
1796        LSQ_DEBUG("invalid packet number 0");
1797        mc->mc_flags |= MC_ERROR;
1798        MCHIST_APPEND(mc, MCHE_PACKET0_IN);
1799        return;
1800    }
1801    if (packet_in->pi_packno > MINICONN_MAX_PACKETS)
1802    {
1803        LSQ_DEBUG("packet number %"PRIu64" is too large (max %zd)",
1804                            packet_in->pi_packno, MINICONN_MAX_PACKETS);
1805        mc->mc_flags |= MC_ERROR;
1806        MCHIST_APPEND(mc, MCHE_PACKET2LARGE_IN);
1807        return;
1808    }
1809    if (MCONN_PACKET_MASK(packet_in->pi_packno) & mc->mc_received_packnos)
1810    {
1811        LSQ_DEBUG("duplicate packet %"PRIu64", ignoring", packet_in->pi_packno);
1812        MCHIST_APPEND(mc, MCHE_PACKET_DUP_IN);
1813        return;
1814    }
1815
1816    if (TAILQ_EMPTY(&mc->mc_deferred))
1817        process_packet(mc, packet_in);
1818    else if (mc->mc_n_deferred < MINI_CONN_MAX_DEFERRED)
1819    {
1820        insert_into_deferred(mc, packet_in);
1821        process_deferred_packets(mc);
1822    }
1823    else
1824        LSQ_DEBUG("won't defer more than %u packets: drop",
1825                                                MINI_CONN_MAX_DEFERRED);
1826}
1827
1828
1829/* Q050 is different is that packet numbers are not known until after the
1830 * packet is decrypted, so we have to follow different logic here.
1831 */
1832static void
1833mini_conn_ci_Q050_packet_in (struct lsquic_conn *lconn,
1834                        struct lsquic_packet_in *packet_in)
1835{
1836    struct mini_conn *mc = (struct mini_conn *) lconn;
1837    enum proc_rp prp;
1838
1839    if (mc->mc_flags & MC_ERROR)
1840    {
1841        LSQ_DEBUG("error state: ignore packet");
1842        return;
1843    }
1844
1845    if (!mc->mc_conn.cn_enc_session)
1846    {
1847        mc->mc_conn.cn_enc_session =
1848            mc->mc_conn.cn_esf.g->esf_create_server(&mc->mc_conn,
1849                                        mc->mc_conn.cn_cid, mc->mc_enpub);
1850        if (!mc->mc_conn.cn_enc_session)
1851        {
1852            LSQ_WARN("cannot create new enc session");
1853            mc->mc_flags |= MC_ERROR;
1854            return;
1855        }
1856        MCHIST_APPEND(mc, MCHE_NEW_ENC_SESS);
1857    }
1858
1859    assert(!(packet_in->pi_flags & PI_DECRYPTED));
1860    prp = conn_decrypt_packet_or(mc, packet_in);
1861    switch (prp)
1862    {
1863    case PRP_KEEP:
1864        break;
1865    case PRP_DROP:
1866        return;
1867    case PRP_ERROR:
1868        mc->mc_flags |= MC_ERROR;
1869        return;
1870    default:
1871        if (mc->mc_n_deferred >= MINI_CONN_MAX_DEFERRED)
1872        {
1873            LSQ_DEBUG("won't defer more than %u packets: drop",
1874                                                MINI_CONN_MAX_DEFERRED);
1875            return;
1876        }
1877        assert(prp == PRP_DEFER);
1878        assert(packet_in->pi_flags & PI_OWN_DATA);
1879        lsquic_packet_in_upref(packet_in);
1880        TAILQ_INSERT_TAIL(&mc->mc_deferred, packet_in, pi_next);
1881        ++mc->mc_n_deferred;
1882        return;
1883    }
1884
1885    assert(prp == PRP_KEEP);
1886    process_packet(mc, packet_in);
1887}
1888
1889
1890static struct lsquic_packet_out *
1891mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
1892{
1893    struct mini_conn *mc = (struct mini_conn *) lconn;
1894    lsquic_packet_out_t *packet_out;
1895
1896    assert(0 == size);
1897    TAILQ_FOREACH(packet_out, &mc->mc_packets_out, po_next)
1898    {
1899        if (packet_out->po_flags & PO_SENT)
1900            continue;
1901        packet_out->po_flags |= PO_SENT;
1902        LSQ_DEBUG("packet_to_send: %"PRIu64, packet_out->po_packno);
1903        return packet_out;
1904    }
1905    return NULL;
1906}
1907
1908
1909static void
1910mini_conn_ci_packet_sent (struct lsquic_conn *lconn,
1911                          struct lsquic_packet_out *packet_out)
1912{
1913    struct mini_conn *mc = (struct mini_conn *) lconn;
1914    mc->mc_sent_packnos |= MCONN_PACKET_MASK(packet_out->po_packno);
1915    if (packet_out->po_frame_types & (1 << QUIC_FRAME_ACK))
1916    {
1917        assert(mc->mc_flags & MC_UNSENT_ACK);
1918        mc->mc_flags &= ~MC_UNSENT_ACK;
1919    }
1920    LSQ_DEBUG("%s: packet %"PRIu64" sent", __func__, packet_out->po_packno);
1921    MCHIST_APPEND(mc, MCHE_PACKET_SENT);
1922}
1923
1924
1925static void
1926mini_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
1927                              struct lsquic_packet_out *packet_out)
1928{
1929    struct mini_conn *mc = (struct mini_conn *) lconn;
1930    packet_out->po_flags &= ~PO_SENT;
1931    LSQ_DEBUG("%s: packet %"PRIu64" not sent", __func__, packet_out->po_packno);
1932    MCHIST_APPEND(mc, MCHE_PACKET_DELAYED);
1933}
1934
1935
1936static void
1937mini_conn_ci_destroy (struct lsquic_conn *lconn)
1938{
1939    assert(!(lconn->cn_flags & LSCONN_HASHED));
1940    struct mini_conn *mc = (struct mini_conn *) lconn;
1941    lsquic_packet_in_t *packet_in;
1942    mconn_packno_set_t still_deferred = 0, in_flight;
1943    enum lsq_log_level log_level;
1944#if LSQUIC_RECORD_INORD_HIST
1945    char inord_str[0x100];
1946#endif
1947    while ((packet_in = TAILQ_FIRST(&mc->mc_packets_in)))
1948    {
1949        TAILQ_REMOVE(&mc->mc_packets_in, packet_in, pi_next);
1950        lsquic_packet_in_put(&mc->mc_enpub->enp_mm, packet_in);
1951    }
1952    while ((packet_in = TAILQ_FIRST(&mc->mc_deferred)))
1953    {
1954        TAILQ_REMOVE(&mc->mc_deferred, packet_in, pi_next);
1955        --mc->mc_n_deferred;
1956        still_deferred |= MCONN_PACKET_MASK(packet_in->pi_packno);
1957        lsquic_packet_in_put(&mc->mc_enpub->enp_mm, packet_in);
1958    }
1959    if (TAILQ_EMPTY(&mc->mc_packets_out))
1960        in_flight = ~0ull;  /* Indicates that packets were dropped before */
1961    else
1962        in_flight = drop_packets_out(mc);
1963    if (mc->mc_conn.cn_enc_session)
1964        mc->mc_conn.cn_esf.g->esf_destroy(mc->mc_conn.cn_enc_session);
1965    log_level = warning_is_warranted(mc) ? LSQ_LOG_WARN : LSQ_LOG_DEBUG;
1966#if LSQUIC_RECORD_INORD_HIST
1967    if (LSQ_LOG_ENABLED(log_level))
1968        inord_to_str(mc, inord_str, sizeof(inord_str));
1969#endif
1970#if LSQUIC_KEEP_MINICONN_HISTORY
1971    const unsigned hist_idx = MCHIST_MASK & mc->mc_hist_idx;
1972    if (MCHE_EMPTY == mc->mc_hist_buf[ hist_idx ])
1973        LSQ_LOG(log_level, "destroyed.  Diagnostics: conn flags: 0x%X, "
1974            "mc flags: 0x%X, "
1975#if LSQUIC_RECORD_INORD_HIST
1976            "incoming-history (trunc: %d) %s, "
1977#endif
1978            "received: %"PRIX64", sent: %"PRIX64", lost: %"PRIX64", "
1979            "deferred: %"PRIX64", still-deferred: %"PRIX64", "
1980            "dropped: %"PRIX64", in-flight: %"PRIX64", acked: %"PRIX64", "
1981            "error_code: 0x%X, ticks: %hu, pack size: %hu, "
1982            "lifetime: %"PRIu64" usec, version: %s, "
1983            "mc hist: %.*s", mc->mc_conn.cn_flags,
1984            mc->mc_flags,
1985#if LSQUIC_RECORD_INORD_HIST
1986            mc->mc_inord_idx >= sizeof(mc->mc_inord_hist) /
1987                                    sizeof(mc->mc_inord_hist[0]), inord_str,
1988#endif
1989            mc->mc_received_packnos, mc->mc_sent_packnos, mc->mc_lost_packnos,
1990            mc->mc_deferred_packnos, still_deferred,
1991            mc->mc_dropped_packnos, in_flight, mc->mc_acked_packnos,
1992            mc->mc_error_code, mc->mc_n_ticks, mc->mc_conn.cn_pack_size,
1993            lsquic_time_now() - mc->mc_created,
1994            lsquic_ver2str[mc->mc_conn.cn_version],
1995            (int) hist_idx, mc->mc_hist_buf);
1996    else
1997        LSQ_LOG(log_level, "destroyed.  Diagnostics: conn flags: 0x%X, "
1998            "mc flags: 0x%X, "
1999#if LSQUIC_RECORD_INORD_HIST
2000            "incoming-history (trunc: %d) %s, "
2001#endif
2002            "received: %"PRIX64", sent: %"PRIX64", lost: %"PRIX64", "
2003            "deferred: %"PRIX64", still-deferred: %"PRIX64", "
2004            "dropped: %"PRIX64", in-flight: %"PRIX64", acked: %"PRIX64", "
2005            "error_code: 0x%X, ticks: %hu, pack size: %hu, "
2006            "lifetime: %"PRIu64" usec, version: %s, "
2007            "mc hist: %.*s%.*s", mc->mc_conn.cn_flags,
2008            mc->mc_flags,
2009#if LSQUIC_RECORD_INORD_HIST
2010            mc->mc_inord_idx >= sizeof(mc->mc_inord_hist) /
2011                                    sizeof(mc->mc_inord_hist[0]), inord_str,
2012#endif
2013            mc->mc_received_packnos, mc->mc_sent_packnos, mc->mc_lost_packnos,
2014            mc->mc_deferred_packnos, still_deferred,
2015            mc->mc_dropped_packnos, in_flight, mc->mc_acked_packnos,
2016            mc->mc_error_code, mc->mc_n_ticks, mc->mc_conn.cn_pack_size,
2017            lsquic_time_now() - mc->mc_created,
2018            lsquic_ver2str[mc->mc_conn.cn_version],
2019            (int) (sizeof(mc->mc_hist_buf) - hist_idx),
2020            mc->mc_hist_buf + hist_idx, (int) hist_idx, mc->mc_hist_buf);
2021#else
2022    LSQ_LOG(log_level, "destroyed.  Diagnostics: conn flags: 0x%X, "
2023        "mc flags: 0x%X, "
2024#if LSQUIC_RECORD_INORD_HIST
2025        "incoming-history (trunc: %d) %s, "
2026#endif
2027        "received: %"PRIX64", sent: %"PRIX64", lost: %"PRIX64", "
2028        "deferred: %"PRIX64", still-deferred: %"PRIX64", "
2029        "dropped: %"PRIX64", in-flight: %"PRIX64", acked: %"PRIX64", "
2030        "error_code: 0x%X, ticks: %hu, pack size: %hu, "
2031        "lifetime: %"PRIu64" usec",
2032        mc->mc_conn.cn_flags,
2033        mc->mc_flags,
2034#if LSQUIC_RECORD_INORD_HIST
2035        mc->mc_inord_idx >= sizeof(mc->mc_inord_hist) /
2036                                sizeof(mc->mc_inord_hist[0]), inord_str,
2037#endif
2038        mc->mc_received_packnos, mc->mc_sent_packnos, mc->mc_lost_packnos,
2039        mc->mc_deferred_packnos, still_deferred,
2040        mc->mc_dropped_packnos, in_flight, mc->mc_acked_packnos,
2041        mc->mc_error_code, mc->mc_n_ticks, mc->mc_path.np_pack_size,
2042        lsquic_time_now() - mc->mc_created);
2043#endif
2044    EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "mini connection destroyed");
2045    lsquic_malo_put(mc);
2046}
2047
2048
2049static struct lsquic_engine *
2050mini_conn_ci_get_engine (struct lsquic_conn *lconn)
2051{
2052    struct mini_conn *mc = (struct mini_conn *) lconn;
2053    return mc->mc_enpub->enp_engine;
2054}
2055
2056
2057static void
2058mini_conn_ci_hsk_done (struct lsquic_conn *lconn, enum lsquic_hsk_status status)
2059{
2060    assert(0);
2061}
2062
2063
2064static int
2065mini_conn_ci_is_tickable (struct lsquic_conn *lconn)
2066{
2067    /* A mini connection is never tickable:  Either there are incoming
2068     * packets, in which case, the connection is going to be ticked, or
2069     * there is an alarm pending, in which case it will be handled via
2070     * the attq.
2071     */
2072    return 0;
2073}
2074
2075
2076static lsquic_time_t
2077mini_conn_ci_next_tick_time (struct lsquic_conn *lconn, unsigned *why)
2078{
2079    struct mini_conn *mc = (struct mini_conn *) lconn;
2080    lsquic_packet_out_t *packet_out;
2081    lsquic_time_t exp_time, retx_time;
2082
2083    exp_time = mc->mc_created + mc->mc_enpub->enp_settings.es_handshake_to;
2084
2085    TAILQ_FOREACH(packet_out, &mc->mc_packets_out, po_next)
2086        if (packet_out->po_flags & PO_SENT)
2087        {
2088            retx_time = packet_out->po_sent + calc_retx_timeout(mc);
2089            if (retx_time < exp_time)
2090            {
2091                *why = N_AEWS + AL_RETX_HSK;
2092                return retx_time;
2093            }
2094            else
2095            {
2096                *why = AEW_MINI_EXPIRE;
2097                return exp_time;
2098            }
2099        }
2100
2101    *why = AEW_MINI_EXPIRE;
2102    return exp_time;
2103}
2104
2105
2106static void
2107mini_conn_ci_client_call_on_new (struct lsquic_conn *lconn)
2108{
2109    assert(0);
2110}
2111
2112
2113static void
2114mini_conn_ci_internal_error (struct lsquic_conn *lconn,
2115                                                    const char *format, ...)
2116{
2117    struct mini_conn *mc = (struct mini_conn *) lconn;
2118    LSQ_INFO("internal error reported");
2119    mc->mc_flags |= MC_ERROR;
2120}
2121
2122
2123/* This function should not be called, as this is specific to IETF QUIC */
2124static void
2125mini_conn_ci_abort_error (struct lsquic_conn *lconn, int is_app,
2126                                unsigned error_code, const char *fmt, ...)
2127{
2128    struct mini_conn *mc = (struct mini_conn *) lconn;
2129    assert(0);
2130    LSQ_WARN("(GQUIC) abort error is called unexpectedly");
2131    mc->mc_flags |= MC_ERROR;
2132}
2133
2134
2135static void
2136mini_conn_ci_tls_alert (struct lsquic_conn *lconn, uint8_t alert)
2137{
2138    assert(0);
2139}
2140
2141
2142static unsigned char
2143mini_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
2144            const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
2145{
2146    struct mini_conn *mc = (struct mini_conn *) lconn;
2147    struct lsquic_packet_out *packet_out;
2148    size_t len;
2149
2150
2151    if (NP_IS_IPv6(&mc->mc_path) != (AF_INET6 == peer_sa->sa_family))
2152        TAILQ_FOREACH(packet_out, &mc->mc_packets_out, po_next)
2153            if ((packet_out->po_flags & (PO_SENT|PO_ENCRYPTED)) == PO_ENCRYPTED)
2154                return_enc_data(mc, packet_out);
2155
2156    len = local_sa->sa_family == AF_INET ? sizeof(struct sockaddr_in)
2157                                                : sizeof(struct sockaddr_in6);
2158
2159    memcpy(mc->mc_path.np_peer_addr, peer_sa, len);
2160    memcpy(mc->mc_path.np_local_addr, local_sa, len);
2161    mc->mc_path.np_peer_ctx = peer_ctx;
2162    return 0;
2163}
2164
2165
2166static struct network_path *
2167mini_conn_ci_get_path (struct lsquic_conn *lconn, const struct sockaddr *sa)
2168{
2169    struct mini_conn *mc = (struct mini_conn *) lconn;
2170
2171    return &mc->mc_path;
2172}
2173
2174
2175static const struct conn_iface mini_conn_iface_standard = {
2176    .ci_abort_error          =  mini_conn_ci_abort_error,
2177    .ci_client_call_on_new   =  mini_conn_ci_client_call_on_new,
2178    .ci_destroy              =  mini_conn_ci_destroy,
2179    .ci_get_engine           =  mini_conn_ci_get_engine,
2180    .ci_get_path             =  mini_conn_ci_get_path,
2181    .ci_hsk_done             =  mini_conn_ci_hsk_done,
2182    .ci_internal_error       =  mini_conn_ci_internal_error,
2183    .ci_is_tickable          =  mini_conn_ci_is_tickable,
2184    .ci_next_packet_to_send  =  mini_conn_ci_next_packet_to_send,
2185    .ci_next_tick_time       =  mini_conn_ci_next_tick_time,
2186    .ci_packet_in            =  mini_conn_ci_packet_in,
2187    .ci_packet_not_sent      =  mini_conn_ci_packet_not_sent,
2188    .ci_packet_sent          =  mini_conn_ci_packet_sent,
2189    .ci_record_addrs         =  mini_conn_ci_record_addrs,
2190    .ci_tick                 =  mini_conn_ci_tick,
2191    .ci_tls_alert            =  mini_conn_ci_tls_alert,
2192};
2193
2194
2195static const struct conn_iface mini_conn_iface_standard_Q050 = {
2196    .ci_abort_error          =  mini_conn_ci_abort_error,
2197    .ci_client_call_on_new   =  mini_conn_ci_client_call_on_new,
2198    .ci_destroy              =  mini_conn_ci_destroy,
2199    .ci_get_engine           =  mini_conn_ci_get_engine,
2200    .ci_get_path             =  mini_conn_ci_get_path,
2201    .ci_hsk_done             =  mini_conn_ci_hsk_done,
2202    .ci_internal_error       =  mini_conn_ci_internal_error,
2203    .ci_is_tickable          =  mini_conn_ci_is_tickable,
2204    .ci_next_packet_to_send  =  mini_conn_ci_next_packet_to_send,
2205    .ci_next_tick_time       =  mini_conn_ci_next_tick_time,
2206    .ci_packet_in            =  mini_conn_ci_Q050_packet_in,
2207    .ci_packet_not_sent      =  mini_conn_ci_packet_not_sent,
2208    .ci_packet_sent          =  mini_conn_ci_packet_sent,
2209    .ci_record_addrs         =  mini_conn_ci_record_addrs,
2210    .ci_tick                 =  mini_conn_ci_tick,
2211    .ci_tls_alert            =  mini_conn_ci_tls_alert,
2212};
2213
2214
2215typedef char largest_recv_holds_at_least_16_seconds[
2216    ((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) / 1000000
2217                                                                    >= 16) - 1];
2218
2219typedef char max_lifespan_smaller_than_largest_recv[
2220    ((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) >
2221                                           MAX_MINI_CONN_LIFESPAN_IN_USEC) - 1];
2222