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