2 2403c80c 2024-03-30 thomas * bufio.c was written by Omar Polo <op@omarpolo.com>
4 94a3f4e9 2024-03-30 thomas * This is free and unencumbered software released into the public domain.
6 94a3f4e9 2024-03-30 thomas * Anyone is free to copy, modify, publish, use, compile, sell, or
7 94a3f4e9 2024-03-30 thomas * distribute this software, either in source code form or as a compiled
8 94a3f4e9 2024-03-30 thomas * binary, for any purpose, commercial or non-commercial, and by any
11 94a3f4e9 2024-03-30 thomas * In jurisdictions that recognize copyright laws, the author or authors
12 94a3f4e9 2024-03-30 thomas * of this software dedicate any and all copyright interest in the
13 94a3f4e9 2024-03-30 thomas * software to the public domain. We make this dedication for the benefit
14 94a3f4e9 2024-03-30 thomas * of the public at large and to the detriment of our heirs and
15 94a3f4e9 2024-03-30 thomas * successors. We intend this dedication to be an overt act of
16 94a3f4e9 2024-03-30 thomas * relinquishment in perpetuity of all present and future rights to this
17 94a3f4e9 2024-03-30 thomas * software under copyright law.
19 94a3f4e9 2024-03-30 thomas * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 94a3f4e9 2024-03-30 thomas * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 94a3f4e9 2024-03-30 thomas * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 94a3f4e9 2024-03-30 thomas * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 94a3f4e9 2024-03-30 thomas * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 94a3f4e9 2024-03-30 thomas * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 94a3f4e9 2024-03-30 thomas * OTHER DEALINGS IN THE SOFTWARE.
28 94a3f4e9 2024-03-30 thomas #include <assert.h>
29 94a3f4e9 2024-03-30 thomas #include <errno.h>
30 94a3f4e9 2024-03-30 thomas #include <stdarg.h>
31 94a3f4e9 2024-03-30 thomas #include <stdint.h>
32 94a3f4e9 2024-03-30 thomas #include <stdio.h>
33 94a3f4e9 2024-03-30 thomas #include <stdlib.h>
34 94a3f4e9 2024-03-30 thomas #include <string.h>
35 94a3f4e9 2024-03-30 thomas #include <tls.h>
36 94a3f4e9 2024-03-30 thomas #include <unistd.h>
38 94a3f4e9 2024-03-30 thomas #include "bufio.h"
41 94a3f4e9 2024-03-30 thomas buf_init(struct buf *buf)
43 94a3f4e9 2024-03-30 thomas const size_t cap = BIO_CHUNK;
45 94a3f4e9 2024-03-30 thomas memset(buf, 0, sizeof(*buf));
46 94a3f4e9 2024-03-30 thomas if ((buf->buf = malloc(cap)) == NULL)
47 94a3f4e9 2024-03-30 thomas return (-1);
48 94a3f4e9 2024-03-30 thomas buf->cap = cap;
49 94a3f4e9 2024-03-30 thomas return (0);
52 94a3f4e9 2024-03-30 thomas static int
53 94a3f4e9 2024-03-30 thomas buf_grow(struct buf *buf)
55 94a3f4e9 2024-03-30 thomas size_t newcap;
58 94a3f4e9 2024-03-30 thomas newcap = buf->cap + BIO_CHUNK;
59 94a3f4e9 2024-03-30 thomas t = realloc(buf->buf, newcap);
60 94a3f4e9 2024-03-30 thomas if (t == NULL)
61 94a3f4e9 2024-03-30 thomas return (-1);
62 94a3f4e9 2024-03-30 thomas buf->buf = t;
63 94a3f4e9 2024-03-30 thomas buf->cap = newcap;
64 94a3f4e9 2024-03-30 thomas return (0);
68 94a3f4e9 2024-03-30 thomas buf_has_line(struct buf *buf, const char *nl)
70 94a3f4e9 2024-03-30 thomas return (memmem(buf->buf, buf->len, nl, strlen(nl)) != NULL);
74 94a3f4e9 2024-03-30 thomas buf_getdelim(struct buf *buf, const char *nl, size_t *len)
76 94a3f4e9 2024-03-30 thomas uint8_t *endl;
77 94a3f4e9 2024-03-30 thomas size_t nlen;
81 94a3f4e9 2024-03-30 thomas nlen = strlen(nl);
82 94a3f4e9 2024-03-30 thomas if ((endl = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
83 94a3f4e9 2024-03-30 thomas return (NULL);
84 94a3f4e9 2024-03-30 thomas *len = endl + nlen - buf->buf;
85 94a3f4e9 2024-03-30 thomas *endl = '\0';
86 94a3f4e9 2024-03-30 thomas return (buf->buf);
90 94a3f4e9 2024-03-30 thomas buf_drain(struct buf *buf, size_t l)
92 94a3f4e9 2024-03-30 thomas buf->cur = 0;
94 94a3f4e9 2024-03-30 thomas if (l >= buf->len) {
95 94a3f4e9 2024-03-30 thomas buf->len = 0;
99 94a3f4e9 2024-03-30 thomas memmove(buf->buf, buf->buf + l, buf->len - l);
100 94a3f4e9 2024-03-30 thomas buf->len -= l;
104 94a3f4e9 2024-03-30 thomas buf_drain_line(struct buf *buf, const char *nl)
106 94a3f4e9 2024-03-30 thomas uint8_t *endln;
107 94a3f4e9 2024-03-30 thomas size_t nlen;
109 94a3f4e9 2024-03-30 thomas nlen = strlen(nl);
110 94a3f4e9 2024-03-30 thomas if ((endln = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
112 94a3f4e9 2024-03-30 thomas buf_drain(buf, endln + nlen - buf->buf);
116 94a3f4e9 2024-03-30 thomas buf_free(struct buf *buf)
118 94a3f4e9 2024-03-30 thomas free(buf->buf);
119 94a3f4e9 2024-03-30 thomas memset(buf, 0, sizeof(*buf));
123 94a3f4e9 2024-03-30 thomas bufio_init(struct bufio *bio)
125 94a3f4e9 2024-03-30 thomas memset(bio, 0, sizeof(*bio));
126 94a3f4e9 2024-03-30 thomas bio->fd = -1;
128 94a3f4e9 2024-03-30 thomas if (buf_init(&bio->wbuf) == -1)
129 94a3f4e9 2024-03-30 thomas return (-1);
130 94a3f4e9 2024-03-30 thomas if (buf_init(&bio->rbuf) == -1) {
131 94a3f4e9 2024-03-30 thomas buf_free(&bio->wbuf);
132 94a3f4e9 2024-03-30 thomas return (-1);
134 94a3f4e9 2024-03-30 thomas return (0);
138 94a3f4e9 2024-03-30 thomas bufio_free(struct bufio *bio)
140 94a3f4e9 2024-03-30 thomas if (bio->ctx)
141 94a3f4e9 2024-03-30 thomas tls_free(bio->ctx);
142 94a3f4e9 2024-03-30 thomas bio->ctx = NULL;
144 94a3f4e9 2024-03-30 thomas if (bio->fd != -1)
145 94a3f4e9 2024-03-30 thomas close(bio->fd);
146 94a3f4e9 2024-03-30 thomas bio->fd = -1;
148 94a3f4e9 2024-03-30 thomas buf_free(&bio->rbuf);
149 94a3f4e9 2024-03-30 thomas buf_free(&bio->wbuf);
153 94a3f4e9 2024-03-30 thomas bufio_close(struct bufio *bio)
155 94a3f4e9 2024-03-30 thomas if (bio->ctx == NULL)
156 94a3f4e9 2024-03-30 thomas return (0);
158 94a3f4e9 2024-03-30 thomas switch (tls_close(bio->ctx)) {
160 94a3f4e9 2024-03-30 thomas return 0;
161 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLIN:
162 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
163 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_READ;
164 94a3f4e9 2024-03-30 thomas return (-1);
165 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLOUT:
166 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
167 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_WRITE;
168 94a3f4e9 2024-03-30 thomas return (-1);
170 94a3f4e9 2024-03-30 thomas return (-1);
175 94a3f4e9 2024-03-30 thomas bufio_reset(struct bufio *bio)
177 94a3f4e9 2024-03-30 thomas bufio_free(bio);
178 94a3f4e9 2024-03-30 thomas return (bufio_init(bio));
182 94a3f4e9 2024-03-30 thomas bufio_set_fd(struct bufio *bio, int fd)
184 94a3f4e9 2024-03-30 thomas bio->fd = fd;
188 94a3f4e9 2024-03-30 thomas bufio_starttls(struct bufio *bio, const char *host, int insecure,
189 94a3f4e9 2024-03-30 thomas const uint8_t *cert, size_t certlen, const uint8_t *key, size_t keylen)
191 94a3f4e9 2024-03-30 thomas struct tls_config *conf;
193 94a3f4e9 2024-03-30 thomas if ((conf = tls_config_new()) == NULL)
194 94a3f4e9 2024-03-30 thomas return (-1);
196 94a3f4e9 2024-03-30 thomas if (insecure) {
197 94a3f4e9 2024-03-30 thomas tls_config_insecure_noverifycert(conf);
198 94a3f4e9 2024-03-30 thomas tls_config_insecure_noverifyname(conf);
199 94a3f4e9 2024-03-30 thomas tls_config_insecure_noverifytime(conf);
202 94a3f4e9 2024-03-30 thomas if (cert && tls_config_set_keypair_mem(conf, cert, certlen,
203 94a3f4e9 2024-03-30 thomas key, keylen) == -1) {
204 94a3f4e9 2024-03-30 thomas tls_config_free(conf);
205 94a3f4e9 2024-03-30 thomas return (-1);
208 94a3f4e9 2024-03-30 thomas if ((bio->ctx = tls_client()) == NULL) {
209 94a3f4e9 2024-03-30 thomas tls_config_free(conf);
210 94a3f4e9 2024-03-30 thomas return (-1);
213 94a3f4e9 2024-03-30 thomas if (tls_configure(bio->ctx, conf) == -1) {
214 94a3f4e9 2024-03-30 thomas tls_config_free(conf);
215 94a3f4e9 2024-03-30 thomas return (-1);
218 94a3f4e9 2024-03-30 thomas tls_config_free(conf);
220 94a3f4e9 2024-03-30 thomas if (tls_connect_socket(bio->ctx, bio->fd, host) == -1)
221 94a3f4e9 2024-03-30 thomas return (-1);
223 94a3f4e9 2024-03-30 thomas return (0);
227 94a3f4e9 2024-03-30 thomas bufio_ev(struct bufio *bio)
229 94a3f4e9 2024-03-30 thomas short ev;
231 94a3f4e9 2024-03-30 thomas if (bio->wantev)
232 94a3f4e9 2024-03-30 thomas return (bio->wantev);
234 94a3f4e9 2024-03-30 thomas ev = BUFIO_WANT_READ;
235 94a3f4e9 2024-03-30 thomas if (bio->wbuf.len != 0)
236 94a3f4e9 2024-03-30 thomas ev |= BUFIO_WANT_WRITE;
238 94a3f4e9 2024-03-30 thomas return (ev);
242 94a3f4e9 2024-03-30 thomas bufio_handshake(struct bufio *bio)
244 94a3f4e9 2024-03-30 thomas if (bio->ctx == NULL) {
245 94a3f4e9 2024-03-30 thomas errno = EINVAL;
246 94a3f4e9 2024-03-30 thomas return (-1);
249 94a3f4e9 2024-03-30 thomas switch (tls_handshake(bio->ctx)) {
251 94a3f4e9 2024-03-30 thomas return (0);
252 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLIN:
253 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
254 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_READ;
255 94a3f4e9 2024-03-30 thomas return (-1);
256 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLOUT:
257 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
258 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_WRITE;
259 94a3f4e9 2024-03-30 thomas return (-1);
261 94a3f4e9 2024-03-30 thomas return (-1);
266 94a3f4e9 2024-03-30 thomas bufio_read(struct bufio *bio)
268 94a3f4e9 2024-03-30 thomas struct buf *rbuf = &bio->rbuf;
269 94a3f4e9 2024-03-30 thomas ssize_t r;
271 94a3f4e9 2024-03-30 thomas assert(rbuf->cap >= rbuf->len);
272 94a3f4e9 2024-03-30 thomas if (rbuf->cap - rbuf->len < BIO_CHUNK) {
273 94a3f4e9 2024-03-30 thomas if (buf_grow(rbuf) == -1)
274 94a3f4e9 2024-03-30 thomas return (-1);
277 94a3f4e9 2024-03-30 thomas if (bio->ctx) {
278 94a3f4e9 2024-03-30 thomas r = tls_read(bio->ctx, rbuf->buf + rbuf->len,
279 94a3f4e9 2024-03-30 thomas rbuf->cap - rbuf->len);
280 94a3f4e9 2024-03-30 thomas switch (r) {
281 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLIN:
282 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
283 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_READ;
284 94a3f4e9 2024-03-30 thomas return (-1);
285 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLOUT:
286 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
287 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_WRITE;
288 94a3f4e9 2024-03-30 thomas return (-1);
290 94a3f4e9 2024-03-30 thomas return (-1);
292 94a3f4e9 2024-03-30 thomas bio->wantev = 0;
293 94a3f4e9 2024-03-30 thomas rbuf->len += r;
294 94a3f4e9 2024-03-30 thomas return (r);
298 94a3f4e9 2024-03-30 thomas r = read(bio->fd, rbuf->buf + rbuf->len, rbuf->cap - rbuf->len);
299 94a3f4e9 2024-03-30 thomas if (r == -1)
300 94a3f4e9 2024-03-30 thomas return (-1);
301 94a3f4e9 2024-03-30 thomas rbuf->len += r;
302 94a3f4e9 2024-03-30 thomas return (r);
306 94a3f4e9 2024-03-30 thomas bufio_drain(struct bufio *bio, void *d, size_t len)
308 94a3f4e9 2024-03-30 thomas struct buf *rbuf = &bio->rbuf;
310 94a3f4e9 2024-03-30 thomas if (len > rbuf->len)
311 94a3f4e9 2024-03-30 thomas len = rbuf->len;
312 94a3f4e9 2024-03-30 thomas memcpy(d, rbuf->buf, len);
313 94a3f4e9 2024-03-30 thomas buf_drain(rbuf, len);
314 94a3f4e9 2024-03-30 thomas return (len);
318 94a3f4e9 2024-03-30 thomas bufio_write(struct bufio *bio)
320 94a3f4e9 2024-03-30 thomas struct buf *wbuf = &bio->wbuf;
321 94a3f4e9 2024-03-30 thomas ssize_t w;
323 94a3f4e9 2024-03-30 thomas if (bio->ctx) {
324 94a3f4e9 2024-03-30 thomas switch (w = tls_write(bio->ctx, wbuf->buf, wbuf->len)) {
325 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLIN:
326 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
327 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_READ;
328 94a3f4e9 2024-03-30 thomas return (-1);
329 94a3f4e9 2024-03-30 thomas case TLS_WANT_POLLOUT:
330 94a3f4e9 2024-03-30 thomas errno = EAGAIN;
331 94a3f4e9 2024-03-30 thomas bio->wantev = BUFIO_WANT_WRITE;
332 94a3f4e9 2024-03-30 thomas return (-1);
334 94a3f4e9 2024-03-30 thomas return (-1);
336 94a3f4e9 2024-03-30 thomas bio->wantev = 0;
337 94a3f4e9 2024-03-30 thomas buf_drain(wbuf, w);
338 94a3f4e9 2024-03-30 thomas return (w);
342 94a3f4e9 2024-03-30 thomas w = write(bio->fd, wbuf->buf, wbuf->len);
343 94a3f4e9 2024-03-30 thomas if (w == -1)
344 94a3f4e9 2024-03-30 thomas return (-1);
345 94a3f4e9 2024-03-30 thomas buf_drain(wbuf, w);
346 94a3f4e9 2024-03-30 thomas return (w);
349 94a3f4e9 2024-03-30 thomas const char *
350 94a3f4e9 2024-03-30 thomas bufio_io_err(struct bufio *bio)
352 94a3f4e9 2024-03-30 thomas if (bio->ctx)
353 94a3f4e9 2024-03-30 thomas return tls_error(bio->ctx);
355 94a3f4e9 2024-03-30 thomas return strerror(errno);
359 94a3f4e9 2024-03-30 thomas bufio_compose(struct bufio *bio, const void *d, size_t len)
361 94a3f4e9 2024-03-30 thomas struct buf *wbuf = &bio->wbuf;
363 94a3f4e9 2024-03-30 thomas while (wbuf->cap - wbuf->len < len) {
364 94a3f4e9 2024-03-30 thomas if (buf_grow(wbuf) == -1)
365 94a3f4e9 2024-03-30 thomas return (-1);
368 94a3f4e9 2024-03-30 thomas memcpy(wbuf->buf + wbuf->len, d, len);
369 94a3f4e9 2024-03-30 thomas wbuf->len += len;
370 94a3f4e9 2024-03-30 thomas return (0);
374 94a3f4e9 2024-03-30 thomas bufio_compose_str(struct bufio *bio, const char *str)
376 94a3f4e9 2024-03-30 thomas return (bufio_compose(bio, str, strlen(str)));
380 94a3f4e9 2024-03-30 thomas bufio_compose_fmt(struct bufio *bio, const char *fmt, ...)
382 94a3f4e9 2024-03-30 thomas va_list ap;
383 94a3f4e9 2024-03-30 thomas char *str;
386 94a3f4e9 2024-03-30 thomas va_start(ap, fmt);
387 94a3f4e9 2024-03-30 thomas r = vasprintf(&str, fmt, ap);
388 94a3f4e9 2024-03-30 thomas va_end(ap);
390 94a3f4e9 2024-03-30 thomas if (r == -1)
391 94a3f4e9 2024-03-30 thomas return (-1);
392 94a3f4e9 2024-03-30 thomas r = bufio_compose(bio, str, r);
393 94a3f4e9 2024-03-30 thomas free(str);
394 94a3f4e9 2024-03-30 thomas return (r);
398 94a3f4e9 2024-03-30 thomas bufio_rewind_cursor(struct bufio *bio)
400 94a3f4e9 2024-03-30 thomas bio->rbuf.cur = 0;
404 94a3f4e9 2024-03-30 thomas bufio_get_cb(void *d)
406 94a3f4e9 2024-03-30 thomas struct bufio *bio = d;
407 94a3f4e9 2024-03-30 thomas struct buf *rbuf = &bio->rbuf;
409 94a3f4e9 2024-03-30 thomas if (rbuf->cur >= rbuf->len)
410 94a3f4e9 2024-03-30 thomas return (EOF);
411 94a3f4e9 2024-03-30 thomas return (rbuf->buf[rbuf->cur++]);
415 94a3f4e9 2024-03-30 thomas bufio_peek_cb(void *d)
417 94a3f4e9 2024-03-30 thomas struct bufio *bio = d;
418 94a3f4e9 2024-03-30 thomas struct buf *rbuf = &bio->rbuf;
420 94a3f4e9 2024-03-30 thomas if (rbuf->cur >= rbuf->len)
421 94a3f4e9 2024-03-30 thomas return (EOF);
422 94a3f4e9 2024-03-30 thomas return (rbuf->buf[rbuf->cur]);