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