/src/h2o/deps/quicly/lib/streambuf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2018 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 <stdlib.h> |
24 | | #include <string.h> |
25 | | #include "quicly/streambuf.h" |
26 | | |
27 | | static void convert_error(quicly_stream_t *stream, int err) |
28 | 0 | { |
29 | 0 | assert(err != 0); |
30 | 0 | if (QUICLY_ERROR_IS_QUIC_APPLICATION(err)) { |
31 | 0 | if (quicly_stream_has_send_side(quicly_is_client(stream->conn), stream->stream_id) && |
32 | 0 | quicly_sendstate_is_open(&stream->sendstate)) |
33 | 0 | quicly_reset_stream(stream, err); |
34 | 0 | if (quicly_stream_has_receive_side(quicly_is_client(stream->conn), stream->stream_id)) |
35 | 0 | quicly_request_stop(stream, err); |
36 | 0 | } else { |
37 | 0 | quicly_close(stream->conn, QUICLY_ERROR_IS_QUIC_TRANSPORT(err) ? err : QUICLY_TRANSPORT_ERROR_INTERNAL, NULL); |
38 | 0 | } |
39 | 0 | } |
40 | | |
41 | | void quicly_sendbuf_dispose(quicly_sendbuf_t *sb) |
42 | 0 | { |
43 | 0 | size_t i; |
44 | |
|
45 | 0 | for (i = 0; i != sb->vecs.size; ++i) { |
46 | 0 | quicly_sendbuf_vec_t *vec = sb->vecs.entries + i; |
47 | 0 | if (vec->cb->discard_vec != NULL) |
48 | 0 | vec->cb->discard_vec(vec); |
49 | 0 | } |
50 | 0 | free(sb->vecs.entries); |
51 | 0 | } |
52 | | |
53 | | void quicly_sendbuf_shift(quicly_stream_t *stream, quicly_sendbuf_t *sb, size_t delta) |
54 | 0 | { |
55 | 0 | size_t i; |
56 | |
|
57 | 0 | for (i = 0; delta != 0; ++i) { |
58 | 0 | assert(i < sb->vecs.size); |
59 | 0 | quicly_sendbuf_vec_t *first_vec = sb->vecs.entries + i; |
60 | 0 | size_t bytes_in_first_vec = first_vec->len - sb->off_in_first_vec; |
61 | 0 | if (delta < bytes_in_first_vec) { |
62 | 0 | sb->off_in_first_vec += delta; |
63 | 0 | break; |
64 | 0 | } |
65 | 0 | delta -= bytes_in_first_vec; |
66 | 0 | if (first_vec->cb->discard_vec != NULL) |
67 | 0 | first_vec->cb->discard_vec(first_vec); |
68 | 0 | sb->off_in_first_vec = 0; |
69 | 0 | } |
70 | 0 | if (i != 0) { |
71 | 0 | if (sb->vecs.size != i) { |
72 | 0 | memmove(sb->vecs.entries, sb->vecs.entries + i, (sb->vecs.size - i) * sizeof(*sb->vecs.entries)); |
73 | 0 | sb->vecs.size -= i; |
74 | 0 | } else { |
75 | 0 | free(sb->vecs.entries); |
76 | 0 | sb->vecs.entries = NULL; |
77 | 0 | sb->vecs.size = 0; |
78 | 0 | sb->vecs.capacity = 0; |
79 | 0 | } |
80 | 0 | } |
81 | 0 | quicly_stream_sync_sendbuf(stream, 0); |
82 | 0 | } |
83 | | |
84 | | void quicly_sendbuf_emit(quicly_stream_t *stream, quicly_sendbuf_t *sb, size_t off, void *dst, size_t *len, int *wrote_all) |
85 | 0 | { |
86 | 0 | size_t vec_index, capacity = *len; |
87 | 0 | int ret; |
88 | |
|
89 | 0 | off += sb->off_in_first_vec; |
90 | 0 | for (vec_index = 0; capacity != 0 && vec_index < sb->vecs.size; ++vec_index) { |
91 | 0 | quicly_sendbuf_vec_t *vec = sb->vecs.entries + vec_index; |
92 | 0 | if (off < vec->len) { |
93 | 0 | size_t bytes_flatten = vec->len - off; |
94 | 0 | int partial = 0; |
95 | 0 | if (capacity < bytes_flatten) { |
96 | 0 | bytes_flatten = capacity; |
97 | 0 | partial = 1; |
98 | 0 | } |
99 | 0 | if ((ret = vec->cb->flatten_vec(vec, dst, off, bytes_flatten)) != 0) { |
100 | 0 | convert_error(stream, ret); |
101 | 0 | return; |
102 | 0 | } |
103 | 0 | dst = (uint8_t *)dst + bytes_flatten; |
104 | 0 | capacity -= bytes_flatten; |
105 | 0 | off = 0; |
106 | 0 | if (partial) |
107 | 0 | break; |
108 | 0 | } else { |
109 | 0 | off -= vec->len; |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | 0 | if (capacity == 0 && vec_index < sb->vecs.size) { |
114 | 0 | *wrote_all = 0; |
115 | 0 | } else { |
116 | 0 | *len = *len - capacity; |
117 | 0 | *wrote_all = 1; |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | static int flatten_raw(quicly_sendbuf_vec_t *vec, void *dst, size_t off, size_t len) |
122 | 0 | { |
123 | 0 | memcpy(dst, (uint8_t *)vec->cbdata + off, len); |
124 | 0 | return 0; |
125 | 0 | } |
126 | | |
127 | | static void discard_raw(quicly_sendbuf_vec_t *vec) |
128 | 0 | { |
129 | 0 | free(vec->cbdata); |
130 | 0 | } |
131 | | |
132 | | int quicly_sendbuf_write(quicly_stream_t *stream, quicly_sendbuf_t *sb, const void *src, size_t len) |
133 | 0 | { |
134 | 0 | static const quicly_streambuf_sendvec_callbacks_t raw_callbacks = {flatten_raw, discard_raw}; |
135 | 0 | quicly_sendbuf_vec_t vec = {&raw_callbacks, len, NULL}; |
136 | 0 | int ret; |
137 | |
|
138 | 0 | assert(quicly_sendstate_is_open(&stream->sendstate)); |
139 | | |
140 | 0 | if ((vec.cbdata = malloc(len)) == NULL) { |
141 | 0 | ret = PTLS_ERROR_NO_MEMORY; |
142 | 0 | goto Error; |
143 | 0 | } |
144 | 0 | memcpy(vec.cbdata, src, len); |
145 | 0 | if ((ret = quicly_sendbuf_write_vec(stream, sb, &vec)) != 0) |
146 | 0 | goto Error; |
147 | 0 | return 0; |
148 | | |
149 | 0 | Error: |
150 | 0 | free(vec.cbdata); |
151 | 0 | return ret; |
152 | 0 | } |
153 | | |
154 | | int quicly_sendbuf_write_vec(quicly_stream_t *stream, quicly_sendbuf_t *sb, quicly_sendbuf_vec_t *vec) |
155 | 0 | { |
156 | 0 | assert(sb->vecs.size <= sb->vecs.capacity); |
157 | | |
158 | 0 | if (sb->vecs.size == sb->vecs.capacity) { |
159 | 0 | quicly_sendbuf_vec_t *new_entries; |
160 | 0 | size_t new_capacity = sb->vecs.capacity == 0 ? 4 : sb->vecs.capacity * 2; |
161 | 0 | if ((new_entries = realloc(sb->vecs.entries, new_capacity * sizeof(*sb->vecs.entries))) == NULL) |
162 | 0 | return PTLS_ERROR_NO_MEMORY; |
163 | 0 | sb->vecs.entries = new_entries; |
164 | 0 | sb->vecs.capacity = new_capacity; |
165 | 0 | } |
166 | 0 | sb->vecs.entries[sb->vecs.size++] = *vec; |
167 | 0 | sb->bytes_written += vec->len; |
168 | |
|
169 | 0 | return quicly_stream_sync_sendbuf(stream, 1); |
170 | 0 | } |
171 | | |
172 | | void quicly_recvbuf_shift(quicly_stream_t *stream, ptls_buffer_t *rb, size_t delta) |
173 | 0 | { |
174 | 0 | assert(delta <= rb->off); |
175 | 0 | rb->off -= delta; |
176 | 0 | memmove(rb->base, rb->base + delta, rb->off); |
177 | |
|
178 | 0 | quicly_stream_sync_recvbuf(stream, delta); |
179 | 0 | } |
180 | | |
181 | | ptls_iovec_t quicly_recvbuf_get(quicly_stream_t *stream, ptls_buffer_t *rb) |
182 | 0 | { |
183 | 0 | size_t avail; |
184 | |
|
185 | 0 | if (quicly_recvstate_transfer_complete(&stream->recvstate)) { |
186 | 0 | avail = rb->off; |
187 | 0 | } else if (stream->recvstate.data_off < stream->recvstate.received.ranges[0].end) { |
188 | 0 | avail = stream->recvstate.received.ranges[0].end - stream->recvstate.data_off; |
189 | 0 | } else { |
190 | 0 | avail = 0; |
191 | 0 | } |
192 | |
|
193 | 0 | return ptls_iovec_init(rb->base, avail); |
194 | 0 | } |
195 | | |
196 | | int quicly_recvbuf_receive(quicly_stream_t *stream, ptls_buffer_t *rb, size_t off, const void *src, size_t len) |
197 | 0 | { |
198 | 0 | if (len != 0) { |
199 | 0 | int ret; |
200 | 0 | if ((ret = ptls_buffer_reserve(rb, off + len - rb->off)) != 0) { |
201 | 0 | convert_error(stream, ret); |
202 | 0 | return -1; |
203 | 0 | } |
204 | 0 | memcpy(rb->base + off, src, len); |
205 | 0 | if (rb->off < off + len) |
206 | 0 | rb->off = off + len; |
207 | 0 | } |
208 | 0 | return 0; |
209 | 0 | } |
210 | | |
211 | | int quicly_streambuf_create(quicly_stream_t *stream, size_t sz) |
212 | 0 | { |
213 | 0 | quicly_streambuf_t *sbuf; |
214 | |
|
215 | 0 | assert(sz >= sizeof(*sbuf)); |
216 | 0 | assert(stream->data == NULL); |
217 | | |
218 | 0 | if ((sbuf = malloc(sz)) == NULL) |
219 | 0 | return PTLS_ERROR_NO_MEMORY; |
220 | 0 | quicly_sendbuf_init(&sbuf->egress); |
221 | 0 | ptls_buffer_init(&sbuf->ingress, "", 0); |
222 | 0 | if (sz != sizeof(*sbuf)) |
223 | 0 | memset((char *)sbuf + sizeof(*sbuf), 0, sz - sizeof(*sbuf)); |
224 | |
|
225 | 0 | stream->data = sbuf; |
226 | 0 | return 0; |
227 | 0 | } |
228 | | |
229 | | void quicly_streambuf_destroy(quicly_stream_t *stream, int err) |
230 | 0 | { |
231 | 0 | quicly_streambuf_t *sbuf = stream->data; |
232 | |
|
233 | 0 | quicly_sendbuf_dispose(&sbuf->egress); |
234 | 0 | ptls_buffer_dispose(&sbuf->ingress); |
235 | 0 | free(sbuf); |
236 | 0 | stream->data = NULL; |
237 | 0 | } |
238 | | |
239 | | void quicly_streambuf_egress_emit(quicly_stream_t *stream, size_t off, void *dst, size_t *len, int *wrote_all) |
240 | 0 | { |
241 | 0 | quicly_streambuf_t *sbuf = stream->data; |
242 | 0 | quicly_sendbuf_emit(stream, &sbuf->egress, off, dst, len, wrote_all); |
243 | 0 | } |
244 | | |
245 | | int quicly_streambuf_egress_shutdown(quicly_stream_t *stream) |
246 | 0 | { |
247 | 0 | quicly_streambuf_t *sbuf = stream->data; |
248 | 0 | quicly_sendstate_shutdown(&stream->sendstate, sbuf->egress.bytes_written); |
249 | 0 | return quicly_stream_sync_sendbuf(stream, 1); |
250 | 0 | } |
251 | | |
252 | | int quicly_streambuf_ingress_receive(quicly_stream_t *stream, size_t off, const void *src, size_t len) |
253 | 0 | { |
254 | 0 | quicly_streambuf_t *sbuf = stream->data; |
255 | 0 | return quicly_recvbuf_receive(stream, &sbuf->ingress, off, src, len); |
256 | 0 | } |