varnish-cache/bin/varnishd/http2/cache_http2_send.c
0
/*-
1
 * Copyright (c) 2016 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 */
30
31
#include "config.h"
32
33
#include <sys/uio.h>
34
35
#include "cache/cache_varnishd.h"
36
37
#include "cache/cache_transport.h"
38
#include "http2/cache_http2.h"
39
40
#include "vend.h"
41
#include "vtim.h"
42
43
#define H2_SEND_HELD(h2, r2) (VTAILQ_FIRST(&(h2)->txqueue) == (r2))
44
45
static int
46 321
h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2)
47
{
48 321
        vtim_dur tmo = 0.;
49
        vtim_real now;
50
        int r;
51
52 321
        AN(cond);
53 321
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
54 321
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
55
56 321
        Lck_AssertHeld(&h2->sess->mtx);
57
58 321
        if (cache_param->idle_send_timeout > 0.)
59 321
                tmo = cache_param->idle_send_timeout;
60
61 321
        r = Lck_CondWaitTimeout(cond, &h2->sess->mtx, tmo);
62 321
        assert(r == 0 || r == ETIMEDOUT);
63
64 321
        now = VTIM_real();
65
66
        /* NB: when we grab idle_send_timeout before acquiring the session
67
         * lock we may time out, but once we wake up both send_timeout and
68
         * idle_send_timeout may have changed meanwhile. For this reason
69
         * h2_stream_tmo() may not log what timed out and we need to call
70
         * again with a magic NAN "now" that indicates to h2_stream_tmo()
71
         * that the stream reached the idle_send_timeout via the lock and
72
         * force it to log it.
73
         */
74 321
        if (h2_stream_tmo(h2, r2, now))
75 50
                r = ETIMEDOUT;
76 271
        else if (r == ETIMEDOUT)
77 25
                AN(h2_stream_tmo(h2, r2, NAN));
78
79 321
        if (r == ETIMEDOUT) {
80 75
                if (r2->error == NULL)
81 75
                        r2->error = H2SE_CANCEL;
82 75
                return (-1);
83
        }
84
85 246
        return (0);
86 321
}
87
88
static void
89 14800
h2_send_get_locked(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
90
{
91
92 14800
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
93 14800
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
94 14800
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
95
96 14800
        Lck_AssertHeld(&h2->sess->mtx);
97 14800
        if (&wrk->cond == h2->cond)
98 6375
                ASSERT_RXTHR(h2);
99 14800
        r2->wrk = wrk;
100 14800
        VTAILQ_INSERT_TAIL(&h2->txqueue, r2, tx_list);
101 14967
        while (!H2_SEND_HELD(h2, r2))
102 167
                AZ(Lck_CondWait(&wrk->cond, &h2->sess->mtx));
103 14800
        r2->wrk = NULL;
104 14800
}
105
106
void
107 14525
H2_Send_Get(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
108
{
109
110 14525
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
111 14525
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
112 14525
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
113
114 14525
        Lck_Lock(&h2->sess->mtx);
115 14525
        h2_send_get_locked(wrk, h2, r2);
116 14525
        Lck_Unlock(&h2->sess->mtx);
117 14525
}
118
119
static void
120 14800
h2_send_rel_locked(struct h2_sess *h2, const struct h2_req *r2)
121
{
122 14800
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
123 14800
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
124
125 14800
        Lck_AssertHeld(&h2->sess->mtx);
126 14800
        AN(H2_SEND_HELD(h2, r2));
127 14800
        VTAILQ_REMOVE(&h2->txqueue, r2, tx_list);
128 14800
        r2 = VTAILQ_FIRST(&h2->txqueue);
129 14800
        if (r2 != NULL) {
130 167
                CHECK_OBJ_NOTNULL(r2->wrk, WORKER_MAGIC);
131 167
                PTOK(pthread_cond_signal(&r2->wrk->cond));
132 167
        }
133 14800
}
134
135
void
136 14525
H2_Send_Rel(struct h2_sess *h2, const struct h2_req *r2)
137
{
138 14525
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
139 14525
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
140
141 14525
        Lck_Lock(&h2->sess->mtx);
142 14525
        h2_send_rel_locked(h2, r2);
143 14525
        Lck_Unlock(&h2->sess->mtx);
144 14525
}
145
146
static void
147 14475
h2_mk_hdr(uint8_t *hdr, h2_frame ftyp, uint8_t flags,
148
    uint32_t len, uint32_t stream)
149
{
150
151 14475
        AN(hdr);
152 14475
        assert(len < (1U << 24));
153 14475
        vbe32enc(hdr, len << 8);
154 14475
        hdr[3] = ftyp->type;
155 14475
        hdr[4] = flags;
156 14475
        vbe32enc(hdr + 5, stream);
157 14475
}
158
159
/*
160
 * This is the "raw" frame sender, all per-stream accounting and
161
 * prioritization must have happened before this is called, and
162
 * the session mtx must be held.
163
 */
164
165
void
166 14475
H2_Send_Frame(struct worker *wrk, struct h2_sess *h2,
167
    h2_frame ftyp, uint8_t flags,
168
    uint32_t len, uint32_t stream, const void *ptr)
169
{
170
        uint8_t hdr[9];
171
        ssize_t s;
172
        struct iovec iov[2];
173
174 14475
        (void)wrk;
175
176 14475
        AN(ftyp);
177 14475
        AZ(flags & ~(ftyp->flags));
178 14475
        if (stream == 0)
179 8525
                AZ(ftyp->act_szero);
180
        else
181 5950
                AZ(ftyp->act_snonzero);
182
183 14475
        h2_mk_hdr(hdr, ftyp, flags, len, stream);
184 14475
        Lck_Lock(&h2->sess->mtx);
185 14475
        VSLb_bin(h2->vsl, SLT_H2TxHdr, 9, hdr);
186 14475
        h2->srq->acct.resp_hdrbytes += 9;
187 14475
        if (ftyp->overhead)
188 10325
                h2->srq->acct.resp_bodybytes += len;
189 14475
        Lck_Unlock(&h2->sess->mtx);
190
191 14475
        memset(iov, 0, sizeof iov);
192 14475
        iov[0].iov_base = (void*)hdr;
193 14475
        iov[0].iov_len = sizeof hdr;
194 14475
        iov[1].iov_base = TRUST_ME(ptr);
195 14475
        iov[1].iov_len = len;
196 14475
        s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2);
197 14475
        if (s != sizeof hdr + len) {
198
                /*
199
                 * There is no point in being nice here, we will be unable
200
                 * to send a GOAWAY once the code unrolls, so go directly
201
                 * to the finale and be done with it.
202
                 */
203 0
                h2->error = H2CE_PROTOCOL_ERROR;
204 14475
        } else if (len > 0) {
205 10500
                Lck_Lock(&h2->sess->mtx);
206 10500
                VSLb_bin(h2->vsl, SLT_H2TxBody, len, ptr);
207 10500
                Lck_Unlock(&h2->sess->mtx);
208 10500
        }
209 14475
}
210
211
static int64_t
212 1250
h2_win_limit(const struct h2_req *r2, const struct h2_sess *h2)
213
{
214
215 1250
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
216 1250
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
217 1250
        CHECK_OBJ_NOTNULL(h2->req0, H2_REQ_MAGIC);
218
219 1250
        Lck_AssertHeld(&h2->sess->mtx);
220 1250
        return (vmin_t(int64_t, r2->t_window, h2->req0->t_window));
221
}
222
223
static void
224 1250
h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w)
225
{
226 1250
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
227 1250
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
228 1250
        CHECK_OBJ_NOTNULL(h2->req0, H2_REQ_MAGIC);
229
230 1250
        Lck_AssertHeld(&h2->sess->mtx);
231 1250
        r2->t_window -= w;
232 1250
        h2->req0->t_window -= w;
233 1250
}
234
235
static h2_error
236 12546
h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2)
237
{
238 12546
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
239 12546
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
240
241 12546
        if (r2->error)
242 1825
                return (r2->error);
243 10721
        if (h2->error && r2->stream > h2->goaway_last_stream)
244 0
                return (h2->error);
245 10721
        return (0);
246 12546
}
247
248
static int64_t
249 2050
h2_do_window(struct worker *wrk, struct h2_req *r2,
250
    struct h2_sess *h2, int64_t wanted)
251
{
252 2050
        int64_t w = 0;
253
254 2050
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
255 2050
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
256 2050
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
257
258 2050
        if (wanted == 0)
259 700
                return (0);
260
261 1350
        Lck_Lock(&h2->sess->mtx);
262 1350
        if (r2->t_window <= 0 || h2->req0->t_window <= 0) {
263 275
                r2->t_winupd = VTIM_real();
264 275
                h2_send_rel_locked(h2, r2);
265 550
                while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) {
266 275
                        r2->cond = &wrk->cond;
267 275
                        (void)h2_cond_wait(r2->cond, h2, r2);
268 275
                        r2->cond = NULL;
269
                }
270 321
                while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0)
271 46
                        (void)h2_cond_wait(h2->winupd_cond, h2, r2);
272
273 275
                if (h2_errcheck(r2, h2) == 0) {
274 175
                        w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted);
275 175
                        h2_win_charge(r2, h2, w);
276 175
                        assert (w > 0);
277 175
                }
278 275
                h2_send_get_locked(wrk, h2, r2);
279 275
        }
280
281 1350
        if (w == 0 && h2_errcheck(r2, h2) == 0) {
282 1075
                assert(r2->t_window > 0);
283 1075
                assert(h2->req0->t_window > 0);
284 1075
                w = h2_win_limit(r2, h2);
285 1075
                if (w > wanted)
286 900
                        w = wanted;
287 1075
                h2_win_charge(r2, h2, w);
288 1075
                assert (w > 0);
289 1075
        }
290 1350
        r2->t_winupd = 0;
291 1350
        Lck_Unlock(&h2->sess->mtx);
292 1350
        return (w);
293 2050
}
294
295
/*
296
 * This is the per-stream frame sender.
297
 * XXX: priority
298
 */
299
300
static void
301 4325
h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags,
302
    uint32_t len, const void *ptr, uint64_t *counter)
303
{
304
        struct h2_sess *h2;
305
        uint32_t mfs, tf;
306
        const char *p;
307
        uint8_t final_flags;
308
309 4325
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
310 4325
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
311 4325
        h2 = r2->h2sess;
312 4325
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
313 4325
        assert(len == 0 || ptr != NULL);
314 4325
        AN(counter);
315
316 4325
        AN(H2_SEND_HELD(h2, r2));
317
318 4325
        if (h2_errcheck(r2, h2))
319 675
                return;
320
321 3650
        AN(ftyp);
322 3650
        AZ(flags & ~(ftyp->flags));
323 3650
        if (r2->stream == 0)
324 0
                AZ(ftyp->act_szero);
325
        else
326 3650
                AZ(ftyp->act_snonzero);
327
328 3650
        Lck_Lock(&h2->sess->mtx);
329 3650
        mfs = h2->remote_settings.max_frame_size;
330 3650
        if (r2->counted && (
331 3650
            (ftyp == H2_F_HEADERS && (flags & H2FF_HEADERS_END_STREAM)) ||
332 1600
            (ftyp == H2_F_DATA && (flags & H2FF_DATA_END_STREAM)) ||
333 0
            ftyp == H2_F_RST_STREAM
334
            )) {
335 5450
                assert(h2->open_streams > 0);
336 1850
                h2->open_streams--;
337 1850
                r2->counted = 0;
338 1850
        }
339 3650
        Lck_Unlock(&h2->sess->mtx);
340
341 3650
        if (ftyp->respect_window) {
342 1600
                tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len);
343 1600
                if (h2_errcheck(r2, h2))
344 0
                        return;
345 1600
                AN(H2_SEND_HELD(h2, r2));
346 1600
        } else
347 2050
                tf = mfs;
348
349 3650
        if (len <= tf) {
350 3400
                H2_Send_Frame(wrk, h2, ftyp, flags, len, r2->stream, ptr);
351 3400
                *counter += len;
352 3400
        } else {
353 250
                AN(ptr);
354 250
                p = ptr;
355 250
                final_flags = ftyp->final_flags & flags;
356 250
                flags &= ~ftyp->final_flags;
357 250
                do {
358 850
                        AN(ftyp->continuation);
359 850
                        if (!ftyp->respect_window)
360 200
                                tf = mfs;
361 850
                        if (ftyp->respect_window && p != ptr) {
362 900
                                tf = h2_do_window(wrk, r2, h2,
363 450
                                    (len > mfs) ? mfs : len);
364 450
                                if (h2_errcheck(r2, h2))
365 100
                                        return;
366 350
                                AN(H2_SEND_HELD(h2, r2));
367 350
                        }
368 750
                        if (tf < len) {
369 1200
                                H2_Send_Frame(wrk, h2, ftyp,
370 600
                                    flags, tf, r2->stream, p);
371 600
                        } else {
372 150
                                if (ftyp->respect_window)
373 100
                                        assert(tf == len);
374 150
                                tf = len;
375 300
                                H2_Send_Frame(wrk, h2, ftyp, final_flags, tf,
376 150
                                    r2->stream, p);
377 150
                                flags = 0;
378
                        }
379 750
                        p += tf;
380 750
                        len -= tf;
381 750
                        *counter += tf;
382 750
                        ftyp = ftyp->continuation;
383 750
                        flags &= ftyp->flags;
384 750
                        final_flags &= ftyp->flags;
385 750
                } while (!h2->error && len > 0);
386
        }
387 4325
}
388
389
void
390 1300
H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2,
391
    uint32_t stream, h2_error h2e)
392
{
393
        char b[4];
394
395 1300
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
396 1300
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
397 1300
        AN(H2_SEND_HELD(h2, r2));
398
399 1300
        Lck_Lock(&h2->sess->mtx);
400 1300
        VSLb(h2->vsl, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt);
401 1300
        Lck_Unlock(&h2->sess->mtx);
402 1300
        vbe32enc(b, h2e->val);
403
404 1300
        H2_Send_Frame(wrk, h2, H2_F_RST_STREAM, 0, sizeof b, stream, b);
405 1300
}
406
407
void
408 4325
H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags,
409
    uint32_t len, const void *ptr, uint64_t *counter)
410
{
411 4325
        uint64_t dummy_counter = 0;
412
413 4325
        if (counter == NULL)
414 1300
                counter = &dummy_counter;
415
416 4325
        h2_send(wrk, r2, ftyp, flags, len, ptr, counter);
417
418 4325
        if (h2_errcheck(r2, r2->h2sess) == H2SE_CANCEL)
419 125
                H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, H2SE_CANCEL);
420 4325
}