Blob


1 /*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
26 #include "config.h"
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
37 #ifndef BUFIO_WITHOUT_TLS
38 #include <tls.h>
39 #endif
41 #include "bufio.h"
43 int
44 buf_init(struct buf *buf)
45 {
46 const size_t cap = BIO_CHUNK;
48 memset(buf, 0, sizeof(*buf));
49 if ((buf->buf = malloc(cap)) == NULL)
50 return (-1);
51 buf->cap = cap;
52 return (0);
53 }
55 static int
56 buf_grow(struct buf *buf)
57 {
58 size_t newcap;
59 void *t;
61 newcap = buf->cap + BIO_CHUNK;
62 t = realloc(buf->buf, newcap);
63 if (t == NULL)
64 return (-1);
65 buf->buf = t;
66 buf->cap = newcap;
67 return (0);
68 }
70 int
71 buf_write(struct buf *buf, const void *d, size_t len)
72 {
73 while (buf->len + len > buf->cap) {
74 if (buf_grow(buf) == -1)
75 return (-1);
76 }
77 memcpy(buf->buf + buf->len, d, len);
78 buf->len += len;
79 return (0);
80 }
82 int
83 buf_has_line(struct buf *buf, const char *nl)
84 {
85 return (memmem(buf->buf, buf->len, nl, strlen(nl)) != NULL);
86 }
88 char *
89 buf_getdelim(struct buf *buf, const char *nl, size_t *len)
90 {
91 uint8_t *endl;
92 size_t nlen;
94 *len = 0;
96 nlen = strlen(nl);
97 if ((endl = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
98 return (NULL);
99 *len = endl + nlen - buf->buf;
100 *endl = '\0';
101 return (buf->buf);
104 void
105 buf_drain(struct buf *buf, size_t l)
107 buf->cur = 0;
109 if (l >= buf->len) {
110 buf->len = 0;
111 return;
114 memmove(buf->buf, buf->buf + l, buf->len - l);
115 buf->len -= l;
118 void
119 buf_drain_line(struct buf *buf, const char *nl)
121 uint8_t *endln;
122 size_t nlen;
124 nlen = strlen(nl);
125 if ((endln = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
126 return;
127 buf_drain(buf, endln + nlen - buf->buf);
130 void
131 buf_free(struct buf *buf)
133 free(buf->buf);
134 memset(buf, 0, sizeof(*buf));
137 int
138 bufio_init(struct bufio *bio)
140 memset(bio, 0, sizeof(*bio));
141 bio->fd = -1;
143 if (buf_init(&bio->wbuf) == -1)
144 return (-1);
145 if (buf_init(&bio->rbuf) == -1) {
146 buf_free(&bio->wbuf);
147 return (-1);
149 return (0);
152 void
153 bufio_free(struct bufio *bio)
155 #ifndef BUFIO_WITHOUT_TLS
156 if (bio->ctx)
157 tls_free(bio->ctx);
158 bio->ctx = NULL;
159 #endif
161 if (bio->fd != -1)
162 close(bio->fd);
163 bio->fd = -1;
165 buf_free(&bio->rbuf);
166 buf_free(&bio->wbuf);
169 int
170 bufio_close(struct bufio *bio)
172 #ifndef BUFIO_WITHOUT_TLS
173 if (bio->ctx == NULL)
174 return (0);
176 switch (tls_close(bio->ctx)) {
177 case 0:
178 return 0;
179 case TLS_WANT_POLLIN:
180 errno = EAGAIN;
181 bio->wantev = BUFIO_WANT_READ;
182 return (-1);
183 case TLS_WANT_POLLOUT:
184 errno = EAGAIN;
185 bio->wantev = BUFIO_WANT_WRITE;
186 return (-1);
187 default:
188 return (-1);
190 #else
191 return (0);
192 #endif
195 int
196 bufio_reset(struct bufio *bio)
198 bufio_free(bio);
199 return (bufio_init(bio));
202 void
203 bufio_set_fd(struct bufio *bio, int fd)
205 bio->fd = fd;
208 void
209 bufio_set_chunked(struct bufio *bio, int chunked)
211 bio->chunked = chunked;
214 int
215 bufio_starttls(struct bufio *bio, const char *host, int insecure,
216 const uint8_t *cert, size_t certlen, const uint8_t *key, size_t keylen)
218 #ifndef BUFIO_WITHOUT_TLS
219 struct tls_config *conf;
221 if ((conf = tls_config_new()) == NULL)
222 return (-1);
224 if (insecure) {
225 tls_config_insecure_noverifycert(conf);
226 tls_config_insecure_noverifyname(conf);
227 tls_config_insecure_noverifytime(conf);
230 if (cert && tls_config_set_keypair_mem(conf, cert, certlen,
231 key, keylen) == -1) {
232 tls_config_free(conf);
233 return (-1);
236 if ((bio->ctx = tls_client()) == NULL) {
237 tls_config_free(conf);
238 return (-1);
241 if (tls_configure(bio->ctx, conf) == -1) {
242 tls_config_free(conf);
243 return (-1);
246 tls_config_free(conf);
248 if (tls_connect_socket(bio->ctx, bio->fd, host) == -1)
249 return (-1);
251 return (0);
252 #else
253 errno = EINVAL;
254 return (-1);
255 #endif
258 int
259 bufio_ev(struct bufio *bio)
261 short ev;
263 if (bio->wantev)
264 return (bio->wantev);
266 ev = BUFIO_WANT_READ;
267 if (bio->wbuf.len != 0)
268 ev |= BUFIO_WANT_WRITE;
270 return (ev);
273 int
274 bufio_handshake(struct bufio *bio)
276 #ifndef BUFIO_WITHOUT_TLS
277 if (bio->ctx == NULL) {
278 errno = EINVAL;
279 return (-1);
282 switch (tls_handshake(bio->ctx)) {
283 case 0:
284 return (0);
285 case TLS_WANT_POLLIN:
286 errno = EAGAIN;
287 bio->wantev = BUFIO_WANT_READ;
288 return (-1);
289 case TLS_WANT_POLLOUT:
290 errno = EAGAIN;
291 bio->wantev = BUFIO_WANT_WRITE;
292 return (-1);
293 default:
294 return (-1);
296 #else
297 errno = EINVAL;
298 return (-1);
299 #endif
302 ssize_t
303 bufio_read(struct bufio *bio)
305 struct buf *rbuf = &bio->rbuf;
306 ssize_t r;
308 assert(rbuf->cap >= rbuf->len);
309 if (rbuf->cap - rbuf->len < BIO_CHUNK) {
310 if (buf_grow(rbuf) == -1)
311 return (-1);
314 #ifndef BUFIO_WITHOUT_TLS
315 if (bio->ctx) {
316 r = tls_read(bio->ctx, rbuf->buf + rbuf->len,
317 rbuf->cap - rbuf->len);
318 switch (r) {
319 case TLS_WANT_POLLIN:
320 errno = EAGAIN;
321 bio->wantev = BUFIO_WANT_READ;
322 return (-1);
323 case TLS_WANT_POLLOUT:
324 errno = EAGAIN;
325 bio->wantev = BUFIO_WANT_WRITE;
326 return (-1);
327 case -1:
328 return (-1);
329 default:
330 bio->wantev = 0;
331 rbuf->len += r;
332 return (r);
335 #endif
337 r = read(bio->fd, rbuf->buf + rbuf->len, rbuf->cap - rbuf->len);
338 if (r == -1)
339 return (-1);
340 rbuf->len += r;
341 return (r);
344 size_t
345 bufio_drain(struct bufio *bio, void *d, size_t len)
347 struct buf *rbuf = &bio->rbuf;
349 if (len > rbuf->len)
350 len = rbuf->len;
351 memcpy(d, rbuf->buf, len);
352 buf_drain(rbuf, len);
353 return (len);
356 ssize_t
357 bufio_write(struct bufio *bio)
359 struct buf *wbuf = &bio->wbuf;
360 ssize_t w;
362 #ifndef BUFIO_WITHOUT_TLS
363 if (bio->ctx) {
364 switch (w = tls_write(bio->ctx, wbuf->buf, wbuf->len)) {
365 case TLS_WANT_POLLIN:
366 errno = EAGAIN;
367 bio->wantev = BUFIO_WANT_READ;
368 return (-1);
369 case TLS_WANT_POLLOUT:
370 errno = EAGAIN;
371 bio->wantev = BUFIO_WANT_WRITE;
372 return (-1);
373 case -1:
374 return (-1);
375 default:
376 bio->wantev = 0;
377 buf_drain(wbuf, w);
378 return (w);
381 #endif
383 w = write(bio->fd, wbuf->buf, wbuf->len);
384 if (w == -1)
385 return (-1);
386 buf_drain(wbuf, w);
387 return (w);
390 static int
391 bufio_append(struct bufio *bio, const void *d, size_t len)
393 struct buf *wbuf = &bio->wbuf;
395 if (len == 0)
396 return (0);
398 while (wbuf->cap - wbuf->len < len) {
399 if (buf_grow(wbuf) == -1)
400 return (-1);
403 memcpy(wbuf->buf + wbuf->len, d, len);
404 wbuf->len += len;
405 return (0);
408 int
409 bufio_compose(struct bufio *bio, const void *d, size_t len)
411 char n[16];
412 int r;
414 if (bio->chunked) {
415 r = snprintf(n, sizeof(n), "%zx\r\n", len);
416 if (r < 0 || (size_t)r >= sizeof(n))
417 return (-1);
418 if (bufio_append(bio, n, r) == -1)
419 return (-1);
422 if (bufio_append(bio, d, len) == -1)
423 return (-1);
425 if (bio->chunked)
426 return bufio_append(bio, "\r\n", 2);
428 return (0);
431 int
432 bufio_compose_str(struct bufio *bio, const char *str)
434 return (bufio_compose(bio, str, strlen(str)));
437 int
438 bufio_compose_fmt(struct bufio *bio, const char *fmt, ...)
440 va_list ap;
441 char *str;
442 int r;
444 va_start(ap, fmt);
445 r = vasprintf(&str, fmt, ap);
446 va_end(ap);
448 if (r == -1)
449 return (-1);
450 r = bufio_compose(bio, str, r);
451 free(str);
452 return (r);
455 void
456 bufio_rewind_cursor(struct bufio *bio)
458 bio->rbuf.cur = 0;
461 int
462 bufio_get_cb(void *d)
464 struct bufio *bio = d;
465 struct buf *rbuf = &bio->rbuf;
467 if (rbuf->cur >= rbuf->len)
468 return (EOF);
469 return (rbuf->buf[rbuf->cur++]);
472 int
473 bufio_peek_cb(void *d)
475 struct bufio *bio = d;
476 struct buf *rbuf = &bio->rbuf;
478 if (rbuf->cur >= rbuf->len)
479 return (EOF);
480 return (rbuf->buf[rbuf->cur]);