Coverage Report

Created: 2025-06-22 06:18

/src/h2o/deps/quicly/lib/frame.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2017 Fastly, Kazuho Oku
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
#include <assert.h>
23
#include <string.h>
24
#include "quicly/frame.h"
25
26
uint8_t *quicly_encode_path_challenge_frame(uint8_t *dst, int is_response, const uint8_t *data)
27
0
{
28
0
    *dst++ = is_response ? QUICLY_FRAME_TYPE_PATH_RESPONSE : QUICLY_FRAME_TYPE_PATH_CHALLENGE;
29
0
    memcpy(dst, data, QUICLY_PATH_CHALLENGE_DATA_LEN);
30
0
    dst += QUICLY_PATH_CHALLENGE_DATA_LEN;
31
0
    return dst;
32
0
}
33
34
uint8_t *quicly_encode_ack_frame(uint8_t *dst, uint8_t *dst_end, quicly_ranges_t *ranges, uint64_t *ecn_counts, uint64_t ack_delay)
35
0
{
36
0
#define WRITE_BLOCK(start, end)                                                                                                    \
37
0
    do {                                                                                                                           \
38
0
        uint64_t _start = (start), _end = (end);                                                                                   \
39
0
        assert(_start < _end);                                                                                                     \
40
0
        if (dst_end - dst < 8)                                                                                                     \
41
0
            return NULL;                                                                                                           \
42
0
        dst = quicly_encodev(dst, _end - _start - 1);                                                                              \
43
0
    } while (0)
44
45
    /* emit ACK_ECN frame if any of the three ECN counts are non-zero */
46
0
    uint8_t frame_type = (ecn_counts[0] | ecn_counts[1] | ecn_counts[2]) != 0 ? QUICLY_FRAME_TYPE_ACK_ECN : QUICLY_FRAME_TYPE_ACK;
47
0
    size_t range_index = ranges->num_ranges - 1;
48
49
0
    assert(ranges->num_ranges != 0);
50
51
    /* number of bytes being emitted without space check are 1 + 8 + 8 + 1 bytes (as defined in QUICLY_ACK_FRAME_CAPACITY) */
52
0
    *dst++ = frame_type;
53
0
    dst = quicly_encodev(dst, ranges->ranges[range_index].end - 1); /* largest acknowledged */
54
0
    dst = quicly_encodev(dst, ack_delay);                           /* ack delay */
55
0
    PTLS_BUILD_ASSERT(QUICLY_MAX_ACK_BLOCKS - 1 <= 63);
56
0
    *dst++ = (uint8_t)(ranges->num_ranges - 1); /* ack blocks */
57
58
0
    while (1) {
59
0
        WRITE_BLOCK(ranges->ranges[range_index].start, ranges->ranges[range_index].end); /* ACK block count */
60
0
        if (range_index-- == 0)
61
0
            break;
62
0
        WRITE_BLOCK(ranges->ranges[range_index].end, ranges->ranges[range_index + 1].start);
63
0
    }
64
65
0
    if (frame_type == QUICLY_FRAME_TYPE_ACK_ECN) {
66
0
        uint8_t buf[24], *p = buf;
67
0
        for (size_t i = 0; i < 3; ++i)
68
0
            p = quicly_encodev(p, ecn_counts[i]);
69
0
        size_t len = p - buf;
70
0
        if (dst_end - dst < len)
71
0
            return NULL;
72
0
        memcpy(dst, buf, len);
73
0
        dst += len;
74
0
    }
75
76
0
    return dst;
77
78
0
#undef WRITE_BLOCK
79
0
}
80
81
quicly_error_t quicly_decode_ack_frame(const uint8_t **src, const uint8_t *end, quicly_ack_frame_t *frame, int is_ack_ecn)
82
0
{
83
0
    uint64_t i, num_gaps, gap, ack_range;
84
85
0
    if ((frame->largest_acknowledged = quicly_decodev(src, end)) == UINT64_MAX)
86
0
        goto Error;
87
0
    if ((frame->ack_delay = quicly_decodev(src, end)) == UINT64_MAX)
88
0
        goto Error;
89
0
    if ((num_gaps = quicly_decodev(src, end)) == UINT64_MAX)
90
0
        goto Error;
91
92
0
    if ((ack_range = quicly_decodev(src, end)) == UINT64_MAX)
93
0
        goto Error;
94
0
    if (frame->largest_acknowledged < ack_range)
95
0
        goto Error;
96
0
    frame->smallest_acknowledged = frame->largest_acknowledged - ack_range;
97
0
    frame->ack_block_lengths[0] = ack_range + 1;
98
0
    frame->num_gaps = 0;
99
100
0
    for (i = 0; i != num_gaps; ++i) {
101
0
        if ((gap = quicly_decodev(src, end)) == UINT64_MAX)
102
0
            goto Error;
103
0
        if ((ack_range = quicly_decodev(src, end)) == UINT64_MAX)
104
0
            goto Error;
105
0
        if (i < QUICLY_ACK_MAX_GAPS) {
106
0
            if (frame->smallest_acknowledged < gap + ack_range + 2)
107
0
                goto Error;
108
0
            frame->gaps[i] = gap + 1;
109
0
            frame->ack_block_lengths[i + 1] = ack_range + 1;
110
0
            frame->smallest_acknowledged -= gap + ack_range + 2;
111
0
            ++frame->num_gaps;
112
0
        }
113
0
    }
114
115
0
    if (is_ack_ecn) {
116
0
        for (i = 0; i < PTLS_ELEMENTSOF(frame->ecn_counts); ++i)
117
0
            if ((frame->ecn_counts[i] = quicly_decodev(src, end)) == UINT64_MAX)
118
0
                goto Error;
119
0
    } else {
120
0
        for (i = 0; i < PTLS_ELEMENTSOF(frame->ecn_counts); ++i)
121
0
            frame->ecn_counts[i] = 0;
122
0
    }
123
124
0
    return 0;
125
0
Error:
126
0
    return QUICLY_TRANSPORT_ERROR_FRAME_ENCODING;
127
0
}
128
129
uint8_t *quicly_encode_close_frame(uint8_t *const base, uint64_t error_code, uint64_t offending_frame_type,
130
                                   const char *reason_phrase)
131
0
{
132
0
    size_t offset = 0, reason_phrase_len = strlen(reason_phrase);
133
134
0
#define PUSHV(v)                                                                                                                   \
135
0
    do {                                                                                                                           \
136
0
        if (base != NULL) {                                                                                                        \
137
0
            offset = quicly_encodev(base + offset, (v)) - base;                                                                    \
138
0
        } else {                                                                                                                   \
139
0
            offset += quicly_encodev_capacity(v);                                                                                  \
140
0
        }                                                                                                                          \
141
0
    } while (0)
142
143
0
    PUSHV(offending_frame_type == UINT64_MAX ? QUICLY_FRAME_TYPE_APPLICATION_CLOSE : QUICLY_FRAME_TYPE_TRANSPORT_CLOSE);
144
0
    PUSHV(error_code);
145
0
    if (offending_frame_type != UINT64_MAX)
146
0
        PUSHV(offending_frame_type);
147
0
    PUSHV(reason_phrase_len);
148
0
    if (base != NULL)
149
0
        memcpy(base + offset, reason_phrase, reason_phrase_len);
150
0
    offset += reason_phrase_len;
151
152
0
#undef PUSHV
153
154
0
    return base + offset;
155
0
}