lsquic_push_promise.h revision 7d09751d
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
2#ifndef LSQUIC_PUSH_PROMISE_H
3#define LSQUIC_PUSH_PROMISE_H 1
4
5struct lsquic_hash_elem;
6struct lsquic_stream;
7
8
9enum push_promise_key_type {
10    PPKT_ID,
11    PPKT_CONTENT,
12};
13
14
15struct push_promise
16{
17    /* A push promise is associated with a single stream, while a stream can
18     * have several push promises it depends on.  These push promises are
19     * stored on a list.  A push promise is destroyed when the dependent
20     * stream is destroyed.  This bounds the amount of time when DUPLICATE_PUSH
21     * frames can be sent out.
22     */
23    SLIST_ENTRY(push_promise)   pp_next;
24    /* Push promises are stored in the same hash and can be searched either
25     * by ID or by content.  To differentiate the two keys, the key type is
26     * appended at the end PPKT_ID or PPKT_CONTENT.
27     */
28    struct lsquic_hash_elem     pp_hash_id,
29                                pp_hash_content;
30    union {
31        uint64_t        id;
32        unsigned char   buf[9];
33    }                           pp_u_id;
34#define pp_id   pp_u_id.id
35    struct lsquic_stream       *pp_pushed_stream;
36    /* This does not include the last key-type byte: */
37    size_t                      pp_content_len;
38    /* Number of streams holding a reference to this push promise.  When this
39     * value becomes zero, the push promise is destroyed.  See lsquic_pp_put().
40     *
41     * The stream on which PUSH_PROMISE frame is sent has a reference in its
42     * sm_promises list.  The push streams themselves have a reference in
43     * sm_promise.
44     */
45    unsigned                    pp_refcnt;
46    /* State for the promise reader.  If the state is not PPWS_NONE, we are
47     * in the process of writing the first push promise on sm_promises list
48     * (that's the last promise received).
49     */
50    enum {
51        PPWS_ID0,       /* Write first byte of Push ID */
52        PPWS_ID1,       /* Write second byte of Push ID */
53        PPWS_ID2,       /* Write third byte of Push ID */
54        PPWS_ID3,       /* Write fourth byte of Push ID */
55        PPWS_ID4,       /* Write fifth byte of Push ID */
56        PPWS_ID5,       /* Write sixth byte of Push ID */
57        PPWS_ID6,       /* Write seventh byte of Push ID */
58        PPWS_ID7,       /* Write eighth byte of Push ID */
59        PPWS_PFX0,      /* Write first NUL byte of the Header Block Prefix */
60        PPWS_PFX1,      /* Write second NUL byte of the Header Block Prefix */
61        PPWS_HBLOCK,    /* Write header block -- use sm_push_hblock_off */
62        PPWS_DONE,
63    }                           pp_write_state;
64    unsigned                    pp_write_off;
65    unsigned char               pp_encoded_push_id[8];
66    /* The content buffer is the header block: it does not include Header
67     * Block Prefix.  It is followed by one-byte key type PPKT_CONTENT.
68     */
69    unsigned char               pp_content_buf[0];
70};
71
72
73#define lsquic_pp_put(promise_, all_promises_) do {                         \
74    if ((promise_)->pp_refcnt > 0) {                                        \
75        --(promise_)->pp_refcnt;                                            \
76        if (0 == (promise_)->pp_refcnt) {                                   \
77            LSQ_DEBUG("destroy push promise %"PRIu64, (promise_)->pp_id);   \
78            if ((promise_)->pp_hash_id.qhe_flags & QHE_HASHED)              \
79                lsquic_hash_erase(all_promises_, &(promise_)->pp_hash_id);  \
80            if ((promise_)->pp_hash_content.qhe_flags & QHE_HASHED)         \
81                lsquic_hash_erase(all_promises_,                            \
82                                            &(promise_)->pp_hash_content);  \
83            free(promise);                                                  \
84        }                                                                   \
85    }                                                                       \
86    else                                                                    \
87        assert(0);                                                          \
88} while (0)
89
90#endif
91