lsquic_packet_out.c revision 50aadb33
1/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_packet_out.c
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/queue.h>
11
12#include "lsquic.h"
13#include "lsquic_int_types.h"
14#include "lsquic_malo.h"
15#include "lsquic_mm.h"
16#include "lsquic_engine_public.h"
17#include "lsquic_packet_common.h"
18#include "lsquic_packet_in.h"
19#include "lsquic_packet_out.h"
20#include "lsquic_parse.h"
21#include "lsquic_sfcw.h"
22#include "lsquic_stream.h"
23#include "lsquic_logger.h"
24
25typedef char _stream_rec_arr_is_at_most_64bytes[
26                                (sizeof(struct stream_rec_arr) <= 64) - 1];
27
28
29struct stream_rec *
30posi_first (struct packet_out_srec_iter *posi,
31            lsquic_packet_out_t *packet_out)
32{
33    posi->packet_out = packet_out;
34    posi->past_srec = 0;
35    return posi_next(posi);
36}
37
38
39struct stream_rec *
40posi_next (struct packet_out_srec_iter *posi)
41{
42    if (posi->past_srec)
43    {
44        while (posi->cur_srec_arr)
45        {
46            for (; posi->srec_idx < sizeof(posi->cur_srec_arr->srecs) / sizeof(posi->cur_srec_arr->srecs[0]);
47                    ++posi->srec_idx)
48            {
49                if (posi->cur_srec_arr->srecs[ posi->srec_idx ].sr_frame_types)
50                    return &posi->cur_srec_arr->srecs[ posi->srec_idx++ ];
51            }
52            posi->cur_srec_arr = STAILQ_NEXT(posi->cur_srec_arr, next_stream_rec_arr);
53            posi->srec_idx = 0;
54        }
55        return NULL;
56    }
57    else
58    {
59        ++posi->past_srec;
60        posi->cur_srec_arr = STAILQ_FIRST(&posi->packet_out->po_srec_arrs);
61        posi->srec_idx = 0;
62        if (posi->packet_out->po_srec.sr_frame_types)
63            return &posi->packet_out->po_srec;
64        return posi_next(posi);
65    }
66}
67
68
69/* Assumption: there can only be one STREAM and only one RST_STREAM frame
70 * for a particular stream per packet.  The latter is true because a stream
71 * will only send out one of them.  The former is true due the way packets
72 * are filled: stream will write out STREAM frame as large as it can.
73 *
74 * Assumption: frames are added to the packet_out in order of their placement
75 * in packet_out->po_data.  There is an assertion in this function that guards
76 * for this.
77 */
78int
79lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
80                              struct lsquic_mm *mm,
81                              struct lsquic_stream *new_stream,
82                              enum QUIC_FRAME_TYPE frame_type,
83                              unsigned short off)
84{
85    struct packet_out_srec_iter posi;
86    struct stream_rec_arr *srec_arr;
87    struct stream_rec *srec;
88
89    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
90        if (srec->sr_stream == new_stream)
91        {
92            switch (frame_type)
93            {
94            case QUIC_FRAME_STREAM:
95                assert(!(srec->sr_frame_types & (1 << QUIC_FRAME_STREAM)));
96                srec->sr_frame_types |= (1 << QUIC_FRAME_STREAM);
97                srec->sr_off         = off;
98                break;
99            default:
100                assert(QUIC_FRAME_RST_STREAM == frame_type);
101                assert(!(srec->sr_frame_types & (1 << QUIC_FRAME_RST_STREAM)));
102                srec->sr_frame_types |= (1 << QUIC_FRAME_RST_STREAM);
103                break;
104            }
105            return 0;                       /* Update existing record */
106        }
107        else if (srec->sr_frame_types & (1 << QUIC_FRAME_STREAM) & (1 << frame_type))
108            assert(srec->sr_off < off);     /* Check that STREAM frames are added in order */
109
110    ++new_stream->n_unacked;
111
112    if (!srec_taken(&packet_out->po_srec))
113    {
114        packet_out->po_srec.sr_frame_types = (1 << frame_type);
115        packet_out->po_srec.sr_stream      = new_stream;
116        packet_out->po_srec.sr_off         = off;
117        return 0;                           /* Insert in first slot */
118    }
119
120    STAILQ_FOREACH(srec_arr, &packet_out->po_srec_arrs, next_stream_rec_arr)
121    {
122        unsigned i;
123        for (i = 0; i < sizeof(srec_arr->srecs) / sizeof(srec_arr->srecs[0]); ++i)
124            if (!srec_taken(&srec_arr->srecs[i]))
125            {
126                srec_arr->srecs[i].sr_frame_types = (1 << frame_type);
127                srec_arr->srecs[i].sr_stream      = new_stream;
128                srec_arr->srecs[i].sr_off         = off;
129                return 0;                   /* Insert in existing srec */
130            }
131    }
132
133    srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
134    if (!srec_arr)
135        return -1;
136
137    memset(srec_arr, 0, sizeof(*srec_arr));
138    srec_arr->srecs[0].sr_frame_types = (1 << frame_type);
139    srec_arr->srecs[0].sr_stream      = new_stream;
140    srec_arr->srecs[0].sr_off         = off;
141    STAILQ_INSERT_TAIL(&packet_out->po_srec_arrs, srec_arr, next_stream_rec_arr);
142    return 0;                               /* Insert in new srec */
143}
144
145
146lsquic_packet_out_t *
147lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
148                unsigned short max_size, enum lsquic_packno_bits bits,
149                const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce)
150{
151    lsquic_packet_out_t *packet_out;
152    enum packet_out_flags flags;
153    unsigned short header_size;
154
155    flags = bits << POBIT_SHIFT;
156    if (ver_tag)
157        flags |= PO_VERSION;
158    if (nonce)
159        flags |= PO_NONCE;
160    if (use_cid)
161        flags |= PO_CONN_ID;
162
163    header_size = lsquic_po_header_length(flags);
164    if (header_size + QUIC_PACKET_HASH_SZ >= max_size)
165    {
166        errno = EINVAL;
167        return NULL;
168    }
169
170    packet_out = lsquic_mm_get_packet_out(mm, malo, max_size - header_size
171                                                - QUIC_PACKET_HASH_SZ);
172    if (!packet_out)
173        return NULL;
174
175    packet_out->po_flags = PO_WRITEABLE | flags;
176    if (ver_tag)
177        packet_out->po_ver_tag = *ver_tag;
178    if (nonce)
179    {
180        /* Nonces are allocated for a very small number of packets.  This
181         * memory is too expensive to carry in every packet.
182         */
183        packet_out->po_nonce = malloc(32);
184        if (!packet_out->po_nonce)
185        {
186            lsquic_mm_put_packet_out(mm, packet_out);
187            return NULL;
188        }
189        memcpy(packet_out->po_nonce, nonce, 32);
190    }
191
192    return packet_out;
193}
194
195
196void
197lsquic_packet_out_destroy (lsquic_packet_out_t *packet_out,
198                           struct lsquic_engine_public *enpub)
199{
200    struct stream_rec_arr *srec_arr;
201    while ((srec_arr = STAILQ_FIRST(&packet_out->po_srec_arrs)))
202    {
203        STAILQ_REMOVE_HEAD(&packet_out->po_srec_arrs, next_stream_rec_arr);
204        lsquic_malo_put(srec_arr);
205    }
206    if (packet_out->po_flags & PO_ENCRYPTED)
207        enpub->enp_pmi->pmi_release(enpub->enp_pmi_ctx,
208                                                packet_out->po_enc_data);
209    if (packet_out->po_nonce)
210        free(packet_out->po_nonce);
211    lsquic_mm_put_packet_out(&enpub->enp_mm, packet_out);
212}
213
214
215/* If `stream_id' is zero, stream frames from all reset streams are elided.
216 * Otherwise, elision is limited to the specified stream.
217 */
218void
219lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
220                                             const struct parse_funcs *pf,
221                                             uint32_t stream_id)
222{
223    struct packet_out_srec_iter posi;
224    struct stream_rec *srec;
225    struct stream_frame frame;
226    unsigned short adj = 0;
227    int n_stream_frames = 0, n_elided = 0;
228    int victim;
229
230    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
231    {
232        if (srec->sr_frame_types & (1 << QUIC_FRAME_STREAM))
233        {
234            ++n_stream_frames;
235
236            /* Offsets of all STREAM frames should be adjusted */
237            srec->sr_off -= adj;
238
239            if (stream_id)
240            {
241                victim = srec->sr_stream->id == stream_id;
242                if (victim)
243                {
244                    assert(lsquic_stream_is_reset(srec->sr_stream));
245                }
246            }
247            else
248                victim = lsquic_stream_is_reset(srec->sr_stream);
249
250            if (victim)
251            {
252                ++n_elided;
253
254                const int len =
255                    pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
256                                packet_out->po_data_sz - srec->sr_off, &frame);
257                if (len < 0)
258                {   /* This is pretty severe: we should be able to parse our own
259                     * frames.  Should this abort the connection?
260                     */
261                    LSQ_ERROR("can't parse our own stream frame");
262                    return;
263                }
264                assert(frame.stream_id == srec->sr_stream->id);
265
266                /* Move the data and adjust sizes */
267                adj += len;
268                memmove(packet_out->po_data + srec->sr_off,
269                        packet_out->po_data + srec->sr_off + len,
270                        packet_out->po_data_sz - srec->sr_off - len);
271                packet_out->po_data_sz -= len;
272
273                /* See what we can do with the stream */
274                srec->sr_frame_types &= ~(1 << QUIC_FRAME_STREAM);
275                if (!srec_taken(srec))
276                    lsquic_stream_acked(srec->sr_stream);
277            }
278        }
279    }
280
281    assert(n_stream_frames);
282    if (n_elided == n_stream_frames)
283        packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM);
284}
285
286
287void
288lsquic_packet_out_chop_regen (lsquic_packet_out_t *packet_out)
289{
290    struct packet_out_srec_iter posi;
291    struct stream_rec *srec;
292    unsigned delta;
293
294    delta = packet_out->po_regen_sz;
295    packet_out->po_data_sz -= delta;
296    memmove(packet_out->po_data, packet_out->po_data + delta,
297                                                    packet_out->po_data_sz);
298    packet_out->po_regen_sz = 0;
299
300    for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
301        if (srec->sr_frame_types & (1 << QUIC_FRAME_STREAM))
302            srec->sr_off -= delta;
303}
304