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
static h2_error
44 7332
h2_errcheck(const struct h2_req *r2, const struct h2_sess *h2)
45
{
46 7332
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
47 7332
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
48
49 7332
        if (r2->error != NULL)
50 1163
                return (r2->error);
51 6169
        if (h2->error != NULL && r2->stream > h2->goaway_last_stream)
52 13
                return (h2->error);
53 6156
        return (NULL);
54 7332
}
55
56
static int
57 165
h2_cond_wait(pthread_cond_t *cond, struct h2_sess *h2, struct h2_req *r2)
58
{
59 165
        vtim_dur tmo = 0.;
60
        vtim_real now;
61
        h2_error h2e;
62
        int r;
63
64 165
        AN(cond);
65 165
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
66 165
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
67
68 165
        Lck_AssertHeld(&h2->sess->mtx);
69
70 165
        if (cache_param->h2_window_timeout > 0.)
71 165
                tmo = cache_param->h2_window_timeout;
72
73 165
        r = Lck_CondWaitTimeout(cond, &h2->sess->mtx, tmo);
74 165
        assert(r == 0 || r == ETIMEDOUT);
75
76 165
        now = VTIM_real();
77
78
        /* NB: when we grab h2_window_timeout before acquiring the session
79
         * lock we may time out, but once we wake up both send_timeout and
80
         * h2_window_timeout may have changed meanwhile. For this reason
81
         * h2_stream_tmo() may not log what timed out and we need to call
82
         * again with a magic NAN "now" that indicates to h2_stream_tmo()
83
         * that the stream reached the h2_window_timeout via the lock and
84
         * force it to log it.
85
         */
86 165
        h2e = h2_stream_tmo(h2, r2, now);
87 165
        if (h2e == NULL && r == ETIMEDOUT) {
88 13
                h2e = h2_stream_tmo(h2, r2, NAN);
89 13
                AN(h2e);
90 13
        }
91
92 165
        if (r2->error == NULL)
93 152
                r2->error = h2e;
94
95 165
        return (h2e != NULL ? -1 : 0);
96
}
97
98
static void
99 10297
h2_send_get_locked(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
100
{
101
102 10297
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
103 10297
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
104 10297
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
105
106 10297
        Lck_AssertHeld(&h2->sess->mtx);
107 10297
        if (&wrk->cond == h2->cond)
108 5290
                ASSERT_RXTHR(h2);
109 10297
        AZ(H2_SEND_HELD(h2, r2));
110 10297
        AZ(r2->wrk);
111 10297
        r2->wrk = wrk;
112 10297
        VTAILQ_INSERT_TAIL(&h2->txqueue, r2, tx_list);
113 10439
        while (!H2_SEND_HELD(h2, r2))
114 142
                AZ(Lck_CondWait(&wrk->cond, &h2->sess->mtx));
115 10297
        r2->wrk = NULL;
116 10297
}
117
118
void
119 10153
H2_Send_Get(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
120
{
121
122 10153
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
123 10153
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
124 10153
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
125
126 10153
        Lck_Lock(&h2->sess->mtx);
127 10153
        h2_send_get_locked(wrk, h2, r2);
128 10153
        Lck_Unlock(&h2->sess->mtx);
129 10153
}
130
131
static void
132 10297
h2_send_rel_locked(struct h2_sess *h2, const struct h2_req *r2)
133
{
134 10297
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
135 10297
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
136
137 10297
        Lck_AssertHeld(&h2->sess->mtx);
138 10297
        AN(H2_SEND_HELD(h2, r2));
139 10297
        VTAILQ_REMOVE(&h2->txqueue, r2, tx_list);
140 10297
        r2 = VTAILQ_FIRST(&h2->txqueue);
141 10297
        if (r2 != NULL) {
142 142
                CHECK_OBJ_NOTNULL(r2->wrk, WORKER_MAGIC);
143 142
                PTOK(pthread_cond_signal(&r2->wrk->cond));
144 142
        }
145 10297
}
146
147
void
148 10154
H2_Send_Rel(struct h2_sess *h2, const struct h2_req *r2)
149
{
150 10154
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
151 10154
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
152
153 10154
        Lck_Lock(&h2->sess->mtx);
154 10154
        h2_send_rel_locked(h2, r2);
155 10154
        Lck_Unlock(&h2->sess->mtx);
156 10154
}
157
158
static void
159 9865
h2_mk_hdr(uint8_t *hdr, h2_frame ftyp, uint8_t flags,
160
    uint32_t len, uint32_t stream)
161
{
162
163 9865
        AN(hdr);
164 9865
        assert(len < (1U << 24));
165 9865
        vbe32enc(hdr, len << 8);
166 9865
        hdr[3] = ftyp->type;
167 9865
        hdr[4] = flags;
168 9865
        vbe32enc(hdr + 5, stream);
169 9865
}
170
171
/*
172
 * This is the "raw" frame sender, all per-stream accounting and
173
 * prioritization must have happened before this is called, and
174
 * the session mtx must be held.
175
 */
176
177
void
178 9865
H2_Send_Frame(struct worker *wrk, struct h2_sess *h2,
179
    h2_frame ftyp, uint8_t flags,
180
    uint32_t len, uint32_t stream, const void *ptr)
181
{
182
        uint8_t hdr[9];
183
        ssize_t s;
184
        struct iovec iov[2];
185
186 9865
        (void)wrk;
187
188 9865
        AN(ftyp);
189 9865
        AZ(flags & ~(ftyp->flags));
190 9865
        if (stream == 0)
191 6370
                AZ(ftyp->act_szero);
192
        else
193 3495
                AZ(ftyp->act_snonzero);
194
195 9865
        h2_mk_hdr(hdr, ftyp, flags, len, stream);
196 9865
        Lck_Lock(&h2->sess->mtx);
197 9865
        VSLb_bin(h2->vsl, SLT_H2TxHdr, 9, hdr);
198 9865
        h2->srq->acct.resp_hdrbytes += 9;
199 9865
        if (ftyp->overhead)
200 7415
                h2->srq->acct.resp_bodybytes += len;
201 9865
        Lck_Unlock(&h2->sess->mtx);
202
203 9865
        memset(iov, 0, sizeof iov);
204 9865
        iov[0].iov_base = (void*)hdr;
205 9865
        iov[0].iov_len = sizeof hdr;
206 9865
        iov[1].iov_base = TRUST_ME(ptr);
207 9865
        iov[1].iov_len = len;
208 9865
        s = writev(h2->sess->fd, iov, len == 0 ? 1 : 2);
209 9865
        if (s != sizeof hdr + len) {
210 31
                if (errno == EWOULDBLOCK) {
211 0
                        H2S_Lock_VSLb(h2, SLT_SessError,
212 0
                             "H2: stream %u: Hit idle_send_timeout", stream);
213 0
                }
214
                else {
215 62
                        H2S_Lock_VSLb(h2, SLT_Debug,
216
                            "H2: stream %u: write error s=%zd/%zu errno=%d",
217 31
                            stream, s, sizeof hdr + len, errno);
218
                }
219
                /*
220
                 * There is no point in being nice here, we will be unable
221
                 * to send a GOAWAY once the code unrolls, so go directly
222
                 * to the finale and be done with it.
223
                 */
224 31
                h2->error = H2CE_PROTOCOL_ERROR;
225 9865
        } else if (len > 0) {
226 7559
                Lck_Lock(&h2->sess->mtx);
227 7559
                VSLb_bin(h2->vsl, SLT_H2TxBody, len, ptr);
228 7559
                Lck_Unlock(&h2->sess->mtx);
229 7559
        }
230 9865
}
231
232
static int64_t
233 655
h2_win_limit(const struct h2_req *r2, const struct h2_sess *h2)
234
{
235
236 655
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
237 655
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
238 655
        CHECK_OBJ_NOTNULL(h2->req0, H2_REQ_MAGIC);
239
240 655
        Lck_AssertHeld(&h2->sess->mtx);
241 655
        return (vmin_t(int64_t, r2->t_window, h2->req0->t_window));
242
}
243
244
static void
245 655
h2_win_charge(struct h2_req *r2, const struct h2_sess *h2, uint32_t w)
246
{
247 655
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
248 655
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
249 655
        CHECK_OBJ_NOTNULL(h2->req0, H2_REQ_MAGIC);
250
251 655
        Lck_AssertHeld(&h2->sess->mtx);
252 655
        r2->t_window -= w;
253 655
        h2->req0->t_window -= w;
254 655
}
255
256
static int64_t
257 1071
h2_do_window(struct worker *wrk, struct h2_req *r2,
258
    struct h2_sess *h2, int64_t wanted)
259
{
260 1071
        int64_t w = 0;
261
262 1071
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
263 1071
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
264 1071
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
265
266 1071
        if (wanted == 0)
267 364
                return (0);
268
269 707
        Lck_Lock(&h2->sess->mtx);
270 707
        if (r2->t_window <= 0 || h2->req0->t_window <= 0) {
271 143
                r2->t_winupd = VTIM_real();
272 143
                h2_send_rel_locked(h2, r2);
273
274 143
                assert(h2->winup_streams >= 0);
275 143
                h2->winup_streams++;
276
277 286
                while (r2->t_window <= 0 && h2_errcheck(r2, h2) == NULL) {
278 143
                        r2->cond = &wrk->cond;
279 143
                        (void)h2_cond_wait(r2->cond, h2, r2);
280 143
                        r2->cond = NULL;
281
                }
282
283 165
                while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == NULL)
284 22
                        (void)h2_cond_wait(h2->winupd_cond, h2, r2);
285
286 143
                if (h2_errcheck(r2, h2) == NULL) {
287 91
                        w = vmin_t(int64_t, h2_win_limit(r2, h2), wanted);
288 91
                        h2_win_charge(r2, h2, w);
289 91
                        assert (w > 0);
290 91
                }
291
292 143
                if (r2->error == H2SE_BROKE_WINDOW &&
293 26
                    h2->open_streams <= h2->winup_streams) {
294 0
                        VSLb(h2->vsl, SLT_SessError, "H2: window bankrupt");
295 0
                        h2->error = r2->error = H2CE_BANKRUPT;
296 0
                    }
297
298 143
                assert(h2->winup_streams > 0);
299 143
                h2->winup_streams--;
300
301 143
                h2_send_get_locked(wrk, h2, r2);
302 143
        }
303
304 707
        if (w == 0 && h2_errcheck(r2, h2) == NULL) {
305 564
                assert(r2->t_window > 0);
306 564
                assert(h2->req0->t_window > 0);
307 564
                w = h2_win_limit(r2, h2);
308 564
                if (w > wanted)
309 473
                        w = wanted;
310 564
                h2_win_charge(r2, h2, w);
311 564
                assert (w > 0);
312 564
        }
313 707
        r2->t_winupd = 0;
314 707
        Lck_Unlock(&h2->sess->mtx);
315 707
        return (w);
316 1071
}
317
318
/*
319
 * This is the per-stream frame sender.
320
 * XXX: priority
321
 */
322
323
static void
324 2649
h2_send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags,
325
    uint32_t len, const void *ptr, uint64_t *counter)
326
{
327
        struct h2_sess *h2;
328
        uint32_t mfs, tf;
329
        const char *p;
330
        uint8_t final_flags;
331
332 2649
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
333 2649
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
334 2649
        h2 = r2->h2sess;
335 2649
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
336 2649
        assert(len == 0 || ptr != NULL);
337 2649
        AN(counter);
338
339 2649
        AN(H2_SEND_HELD(h2, r2));
340
341 2649
        if (h2_errcheck(r2, h2) != NULL)
342 459
                return;
343
344 2190
        AN(ftyp);
345 2190
        AZ(flags & ~(ftyp->flags));
346 2190
        if (r2->stream == 0)
347 0
                AZ(ftyp->act_szero);
348
        else
349 2190
                AZ(ftyp->act_snonzero);
350
351 2190
        Lck_Lock(&h2->sess->mtx);
352 2190
        mfs = h2->remote_settings.max_frame_size;
353 2190
        if (r2->counted && (
354 2190
            (ftyp == H2_F_HEADERS && (flags & H2FF_HEADERS_END_STREAM)) ||
355 837
            (ftyp == H2_F_DATA && (flags & H2FF_DATA_END_STREAM)) ||
356 0
            ftyp == H2_F_RST_STREAM
357
            )) {
358 3145
                assert(h2->open_streams > 0);
359 1235
                h2->open_streams--;
360 1235
                r2->counted = 0;
361 1235
        }
362 2190
        Lck_Unlock(&h2->sess->mtx);
363
364 2190
        if (ftyp->respect_window) {
365 837
                tf = h2_do_window(wrk, r2, h2, (len > mfs) ? mfs : len);
366 837
                if (h2_errcheck(r2, h2) != NULL)
367 0
                        return;
368 837
                AN(H2_SEND_HELD(h2, r2));
369 837
        } else
370 1353
                tf = mfs;
371
372 2190
        if (len <= tf) {
373 2060
                H2_Send_Frame(wrk, h2, ftyp, flags, len, r2->stream, ptr);
374 2060
                *counter += len;
375 2060
        } else {
376 130
                AN(ptr);
377 130
                p = ptr;
378 130
                final_flags = ftyp->final_flags & flags;
379 130
                flags &= ~ftyp->final_flags;
380 130
                do {
381 442
                        AN(ftyp->continuation);
382 442
                        if (!ftyp->respect_window)
383 104
                                tf = mfs;
384 442
                        if (ftyp->respect_window && p != ptr) {
385 468
                                tf = h2_do_window(wrk, r2, h2,
386 234
                                    (len > mfs) ? mfs : len);
387 234
                                if (h2_errcheck(r2, h2) != NULL)
388 52
                                        return;
389 182
                                AN(H2_SEND_HELD(h2, r2));
390 182
                        }
391 390
                        if (tf < len) {
392 624
                                H2_Send_Frame(wrk, h2, ftyp,
393 312
                                    flags, tf, r2->stream, p);
394 312
                        } else {
395 78
                                if (ftyp->respect_window)
396 52
                                        assert(tf == len);
397 78
                                tf = len;
398 156
                                H2_Send_Frame(wrk, h2, ftyp, final_flags, tf,
399 78
                                    r2->stream, p);
400 78
                                flags = 0;
401
                        }
402 390
                        p += tf;
403 390
                        len -= tf;
404 390
                        *counter += tf;
405 390
                        ftyp = ftyp->continuation;
406 390
                        flags &= ftyp->flags;
407 390
                        final_flags &= ftyp->flags;
408 390
                } while (h2->error == NULL && len > 0);
409
        }
410 2649
}
411
412
void
413 785
H2_Send_RST(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2,
414
    uint32_t stream, h2_error h2e)
415
{
416
        char b[4];
417 785
        h2_error h2e_rr = NULL;
418
419 785
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
420 785
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
421 785
        AN(H2_SEND_HELD(h2, r2));
422 785
        AN(h2e);
423
424 785
        H2S_Lock_VSLb(h2, SLT_Debug, "H2: stream %u: %s", stream, h2e->txt);
425 785
        vbe32enc(b, h2e->val);
426
427 785
        H2_Send_Frame(wrk, h2, H2_F_RST_STREAM, 0, sizeof b, stream, b);
428
429 785
        if (h2_rapid_reset_check(wrk, h2, r2))
430 702
                h2e_rr = h2_rapid_reset_charge(wrk, h2, r2);
431 785
        if (h2e_rr != NULL)
432 13
                h2->error = h2e_rr;
433 785
}
434
435
void
436 1898
H2_Send_GOAWAY(struct worker *wrk, struct h2_sess *h2, const struct h2_req *r2,
437
    h2_error h2e)
438
{
439
        char b[8];
440
441 1898
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
442 1898
        CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
443 1898
        AN(H2_SEND_HELD(h2, r2));
444 1898
        AN(h2e);
445
446 1898
        if (h2->goaway)
447 0
                return;
448
449 1898
        vbe32enc(b, h2->highest_stream);
450 1898
        vbe32enc(b + 4, h2e->val);
451 1898
        H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b);
452 1898
        h2->goaway = 1;
453 1898
}
454
455
void
456 2649
H2_Send(struct worker *wrk, struct h2_req *r2, h2_frame ftyp, uint8_t flags,
457
    uint32_t len, const void *ptr, uint64_t *counter)
458
{
459 2649
        uint64_t dummy_counter = 0;
460
        h2_error h2e;
461
462 2649
        if (counter == NULL)
463 759
                counter = &dummy_counter;
464
465 2649
        h2_send(wrk, r2, ftyp, flags, len, ptr, counter);
466
467 2649
        h2e = h2_errcheck(r2, r2->h2sess);
468 2649
        if (H2_ERROR_MATCH(h2e, H2SE_CANCEL))
469 65
                H2_Send_RST(wrk, r2->h2sess, r2, r2->stream, h2e);
470 2649
}