Blob


1 /*
2 * bufio.c was written by Omar Polo <op@omarpolo.com>
3 *
4 * This is free and unencumbered software released into the public domain.
5 *
6 * Anyone is free to copy, modify, publish, use, compile, sell, or
7 * distribute this software, either in source code form or as a compiled
8 * binary, for any purpose, commercial or non-commercial, and by any
9 * means.
10 *
11 * In jurisdictions that recognize copyright laws, the author or authors
12 * of this software dedicate any and all copyright interest in the
13 * software to the public domain. We make this dedication for the benefit
14 * of the public at large and to the detriment of our heirs and
15 * successors. We intend this dedication to be an overt act of
16 * relinquishment in perpetuity of all present and future rights to this
17 * software under copyright law.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
28 #include "got_compat.h"
30 #include <assert.h>
31 #include <errno.h>
32 #include <stdarg.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <tls.h>
37 #include <string.h>
38 #include <unistd.h>
40 #include "bufio.h"
42 int
43 buf_init(struct buf *buf)
44 {
45 const size_t cap = BIO_CHUNK;
47 memset(buf, 0, sizeof(*buf));
48 if ((buf->buf = malloc(cap)) == NULL)
49 return (-1);
50 buf->cap = cap;
51 return (0);
52 }
54 static int
55 buf_grow(struct buf *buf)
56 {
57 size_t newcap;
58 void *t;
60 newcap = buf->cap + BIO_CHUNK;
61 t = realloc(buf->buf, newcap);
62 if (t == NULL)
63 return (-1);
64 buf->buf = t;
65 buf->cap = newcap;
66 return (0);
67 }
69 int
70 buf_has_line(struct buf *buf, const char *nl)
71 {
72 return (memmem(buf->buf, buf->len, nl, strlen(nl)) != NULL);
73 }
75 char *
76 buf_getdelim(struct buf *buf, const char *nl, size_t *len)
77 {
78 uint8_t *endl;
79 size_t nlen;
81 *len = 0;
83 nlen = strlen(nl);
84 if ((endl = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
85 return (NULL);
86 *len = endl + nlen - buf->buf;
87 *endl = '\0';
88 return (buf->buf);
89 }
91 void
92 buf_drain(struct buf *buf, size_t l)
93 {
94 buf->cur = 0;
96 if (l >= buf->len) {
97 buf->len = 0;
98 return;
99 }
101 memmove(buf->buf, buf->buf + l, buf->len - l);
102 buf->len -= l;
105 void
106 buf_drain_line(struct buf *buf, const char *nl)
108 uint8_t *endln;
109 size_t nlen;
111 nlen = strlen(nl);
112 if ((endln = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
113 return;
114 buf_drain(buf, endln + nlen - buf->buf);
117 void
118 buf_free(struct buf *buf)
120 free(buf->buf);
121 memset(buf, 0, sizeof(*buf));
124 int
125 bufio_init(struct bufio *bio)
127 memset(bio, 0, sizeof(*bio));
128 bio->fd = -1;
130 if (buf_init(&bio->wbuf) == -1)
131 return (-1);
132 if (buf_init(&bio->rbuf) == -1) {
133 buf_free(&bio->wbuf);
134 return (-1);
136 return (0);
139 void
140 bufio_free(struct bufio *bio)
142 if (bio->ctx)
143 tls_free(bio->ctx);
144 bio->ctx = NULL;
146 if (bio->fd != -1)
147 close(bio->fd);
148 bio->fd = -1;
150 buf_free(&bio->rbuf);
151 buf_free(&bio->wbuf);
154 int
155 bufio_close(struct bufio *bio)
157 if (bio->ctx == NULL)
158 return (0);
160 switch (tls_close(bio->ctx)) {
161 case 0:
162 return 0;
163 case TLS_WANT_POLLIN:
164 errno = EAGAIN;
165 bio->wantev = BUFIO_WANT_READ;
166 return (-1);
167 case TLS_WANT_POLLOUT:
168 errno = EAGAIN;
169 bio->wantev = BUFIO_WANT_WRITE;
170 return (-1);
171 default:
172 return (-1);
176 int
177 bufio_reset(struct bufio *bio)
179 bufio_free(bio);
180 return (bufio_init(bio));
183 void
184 bufio_set_fd(struct bufio *bio, int fd)
186 bio->fd = fd;
189 int
190 bufio_starttls(struct bufio *bio, const char *host, int insecure,
191 const uint8_t *cert, size_t certlen, const uint8_t *key, size_t keylen)
193 struct tls_config *conf;
195 if ((conf = tls_config_new()) == NULL)
196 return (-1);
198 if (insecure) {
199 tls_config_insecure_noverifycert(conf);
200 tls_config_insecure_noverifyname(conf);
201 tls_config_insecure_noverifytime(conf);
204 if (cert && tls_config_set_keypair_mem(conf, cert, certlen,
205 key, keylen) == -1) {
206 tls_config_free(conf);
207 return (-1);
210 if ((bio->ctx = tls_client()) == NULL) {
211 tls_config_free(conf);
212 return (-1);
215 if (tls_configure(bio->ctx, conf) == -1) {
216 tls_config_free(conf);
217 return (-1);
220 tls_config_free(conf);
222 if (tls_connect_socket(bio->ctx, bio->fd, host) == -1)
223 return (-1);
225 return (0);
228 int
229 bufio_ev(struct bufio *bio)
231 short ev;
233 if (bio->wantev)
234 return (bio->wantev);
236 ev = BUFIO_WANT_READ;
237 if (bio->wbuf.len != 0)
238 ev |= BUFIO_WANT_WRITE;
240 return (ev);
243 int
244 bufio_handshake(struct bufio *bio)
246 if (bio->ctx == NULL) {
247 errno = EINVAL;
248 return (-1);
251 switch (tls_handshake(bio->ctx)) {
252 case 0:
253 return (0);
254 case TLS_WANT_POLLIN:
255 errno = EAGAIN;
256 bio->wantev = BUFIO_WANT_READ;
257 return (-1);
258 case TLS_WANT_POLLOUT:
259 errno = EAGAIN;
260 bio->wantev = BUFIO_WANT_WRITE;
261 return (-1);
262 default:
263 return (-1);
267 ssize_t
268 bufio_read(struct bufio *bio)
270 struct buf *rbuf = &bio->rbuf;
271 ssize_t r;
273 assert(rbuf->cap >= rbuf->len);
274 if (rbuf->cap - rbuf->len < BIO_CHUNK) {
275 if (buf_grow(rbuf) == -1)
276 return (-1);
279 if (bio->ctx) {
280 r = tls_read(bio->ctx, rbuf->buf + rbuf->len,
281 rbuf->cap - rbuf->len);
282 switch (r) {
283 case TLS_WANT_POLLIN:
284 errno = EAGAIN;
285 bio->wantev = BUFIO_WANT_READ;
286 return (-1);
287 case TLS_WANT_POLLOUT:
288 errno = EAGAIN;
289 bio->wantev = BUFIO_WANT_WRITE;
290 return (-1);
291 case -1:
292 bio->wantev = 0;
293 errno = 0;
294 return (-1);
295 default:
296 bio->wantev = 0;
297 rbuf->len += r;
298 return (r);
302 r = read(bio->fd, rbuf->buf + rbuf->len, rbuf->cap - rbuf->len);
303 if (r == -1)
304 return (-1);
305 rbuf->len += r;
306 return (r);
309 size_t
310 bufio_drain(struct bufio *bio, void *d, size_t len)
312 struct buf *rbuf = &bio->rbuf;
314 if (len > rbuf->len)
315 len = rbuf->len;
316 memcpy(d, rbuf->buf, len);
317 buf_drain(rbuf, len);
318 return (len);
321 ssize_t
322 bufio_write(struct bufio *bio)
324 struct buf *wbuf = &bio->wbuf;
325 ssize_t w;
327 if (bio->ctx) {
328 switch (w = tls_write(bio->ctx, wbuf->buf, wbuf->len)) {
329 case TLS_WANT_POLLIN:
330 errno = EAGAIN;
331 bio->wantev = BUFIO_WANT_READ;
332 return (-1);
333 case TLS_WANT_POLLOUT:
334 errno = EAGAIN;
335 bio->wantev = BUFIO_WANT_WRITE;
336 return (-1);
337 case -1:
338 return (-1);
339 default:
340 bio->wantev = 0;
341 buf_drain(wbuf, w);
342 return (w);
346 w = write(bio->fd, wbuf->buf, wbuf->len);
347 if (w == -1)
348 return (-1);
349 buf_drain(wbuf, w);
350 return (w);
353 const char *
354 bufio_io_err(struct bufio *bio)
356 if (bio->ctx)
357 return tls_error(bio->ctx);
359 return strerror(errno);
362 int
363 bufio_compose(struct bufio *bio, const void *d, size_t len)
365 struct buf *wbuf = &bio->wbuf;
367 while (wbuf->cap - wbuf->len < len) {
368 if (buf_grow(wbuf) == -1)
369 return (-1);
372 memcpy(wbuf->buf + wbuf->len, d, len);
373 wbuf->len += len;
374 return (0);
377 int
378 bufio_compose_str(struct bufio *bio, const char *str)
380 return (bufio_compose(bio, str, strlen(str)));
383 int
384 bufio_compose_fmt(struct bufio *bio, const char *fmt, ...)
386 va_list ap;
387 char *str;
388 int r;
390 va_start(ap, fmt);
391 r = vasprintf(&str, fmt, ap);
392 va_end(ap);
394 if (r == -1)
395 return (-1);
396 r = bufio_compose(bio, str, r);
397 free(str);
398 return (r);
401 void
402 bufio_rewind_cursor(struct bufio *bio)
404 bio->rbuf.cur = 0;
407 int
408 bufio_get_cb(void *d)
410 struct bufio *bio = d;
411 struct buf *rbuf = &bio->rbuf;
413 if (rbuf->cur >= rbuf->len)
414 return (EOF);
415 return (rbuf->buf[rbuf->cur++]);
418 int
419 bufio_peek_cb(void *d)
421 struct bufio *bio = d;
422 struct buf *rbuf = &bio->rbuf;
424 if (rbuf->cur >= rbuf->len)
425 return (EOF);
426 return (rbuf->buf[rbuf->cur]);