Blob


1 /* $OpenBSD: iobuf.c,v 1.11 2019/06/12 17:42:53 eric Exp $ */
2 /*
3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
18 #define _GNU_SOURCE 1
19 #define _BSD_SOURCE 1
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/uio.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
33 #ifdef IO_TLS
34 #include <openssl/err.h>
35 #include <openssl/ssl.h>
36 #endif
38 #include "openbsd-compat.h"
39 #include "iobuf.h"
41 #define IOBUF_MAX 65536
42 #define IOBUFQ_MIN 4096
44 struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t);
45 void iobuf_drain(struct iobuf *, size_t);
47 int
48 iobuf_init(struct iobuf *io, size_t size, size_t max)
49 {
50 memset(io, 0, sizeof *io);
52 if (max == 0)
53 max = IOBUF_MAX;
55 if (size == 0)
56 size = max;
58 if (size > max)
59 return (-1);
61 if ((io->buf = calloc(size, 1)) == NULL)
62 return (-1);
64 io->size = size;
65 io->max = max;
67 return (0);
68 }
70 void
71 iobuf_clear(struct iobuf *io)
72 {
73 struct ioqbuf *q;
75 free(io->buf);
77 while ((q = io->outq)) {
78 io->outq = q->next;
79 free(q);
80 }
82 memset(io, 0, sizeof (*io));
83 }
85 void
86 iobuf_drain(struct iobuf *io, size_t n)
87 {
88 struct ioqbuf *q;
89 size_t left = n;
91 while ((q = io->outq) && left) {
92 if ((q->wpos - q->rpos) > left) {
93 q->rpos += left;
94 left = 0;
95 } else {
96 left -= q->wpos - q->rpos;
97 io->outq = q->next;
98 free(q);
99 }
102 io->queued -= (n - left);
103 if (io->outq == NULL)
104 io->outqlast = NULL;
107 int
108 iobuf_extend(struct iobuf *io, size_t n)
110 char *t;
112 if (n > io->max)
113 return (-1);
115 if (io->max - io->size < n)
116 return (-1);
118 t = recallocarray(io->buf, io->size, io->size + n, 1);
119 if (t == NULL)
120 return (-1);
122 io->size += n;
123 io->buf = t;
125 return (0);
128 size_t
129 iobuf_left(struct iobuf *io)
131 return io->size - io->wpos;
134 size_t
135 iobuf_space(struct iobuf *io)
137 return io->size - (io->wpos - io->rpos);
140 size_t
141 iobuf_len(struct iobuf *io)
143 return io->wpos - io->rpos;
146 char *
147 iobuf_data(struct iobuf *io)
149 return io->buf + io->rpos;
152 void
153 iobuf_drop(struct iobuf *io, size_t n)
155 if (n >= iobuf_len(io)) {
156 io->rpos = io->wpos = 0;
157 return;
160 io->rpos += n;
163 char *
164 iobuf_getline(struct iobuf *iobuf, size_t *rlen)
166 char *buf;
167 size_t len, i;
169 buf = iobuf_data(iobuf);
170 len = iobuf_len(iobuf);
172 for (i = 0; i + 1 <= len; i++)
173 if (buf[i] == '\n') {
174 /* Note: the returned address points into the iobuf
175 * buffer. We NUL-end it for convenience, and discard
176 * the data from the iobuf, so that the caller doesn't
177 * have to do it. The data remains "valid" as long
178 * as the iobuf does not overwrite it, that is until
179 * the next call to iobuf_normalize() or iobuf_extend().
180 */
181 iobuf_drop(iobuf, i + 1);
182 len = (i && buf[i - 1] == '\r') ? i - 1 : i;
183 buf[len] = '\0';
184 if (rlen)
185 *rlen = len;
186 return (buf);
189 return (NULL);
192 void
193 iobuf_normalize(struct iobuf *io)
195 if (io->rpos == 0)
196 return;
198 if (io->rpos == io->wpos) {
199 io->rpos = io->wpos = 0;
200 return;
203 memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos);
204 io->wpos -= io->rpos;
205 io->rpos = 0;
208 ssize_t
209 iobuf_read(struct iobuf *io, int fd)
211 ssize_t n;
213 n = read(fd, io->buf + io->wpos, iobuf_left(io));
214 if (n == -1) {
215 /* XXX is this really what we want? */
216 if (errno == EAGAIN || errno == EINTR)
217 return (IOBUF_WANT_READ);
218 return (IOBUF_ERROR);
220 if (n == 0)
221 return (IOBUF_CLOSED);
223 io->wpos += n;
225 return (n);
228 struct ioqbuf *
229 ioqbuf_alloc(struct iobuf *io, size_t len)
231 struct ioqbuf *q;
233 if (len < IOBUFQ_MIN)
234 len = IOBUFQ_MIN;
236 if ((q = malloc(sizeof(*q) + len)) == NULL)
237 return (NULL);
239 q->rpos = 0;
240 q->wpos = 0;
241 q->size = len;
242 q->next = NULL;
243 q->buf = (char *)(q) + sizeof(*q);
245 if (io->outqlast == NULL)
246 io->outq = q;
247 else
248 io->outqlast->next = q;
249 io->outqlast = q;
251 return (q);
254 size_t
255 iobuf_queued(struct iobuf *io)
257 return io->queued;
260 void *
261 iobuf_reserve(struct iobuf *io, size_t len)
263 struct ioqbuf *q;
264 void *r;
266 if (len == 0)
267 return (NULL);
269 if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) {
270 if ((q = ioqbuf_alloc(io, len)) == NULL)
271 return (NULL);
274 r = q->buf + q->wpos;
275 q->wpos += len;
276 io->queued += len;
278 return (r);
281 int
282 iobuf_queue(struct iobuf *io, const void *data, size_t len)
284 void *buf;
286 if (len == 0)
287 return (0);
289 if ((buf = iobuf_reserve(io, len)) == NULL)
290 return (-1);
292 memmove(buf, data, len);
294 return (len);
297 int
298 iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt)
300 int i;
301 size_t len = 0;
302 char *buf;
304 for (i = 0; i < iovcnt; i++)
305 len += iov[i].iov_len;
307 if ((buf = iobuf_reserve(io, len)) == NULL)
308 return (-1);
310 for (i = 0; i < iovcnt; i++) {
311 if (iov[i].iov_len == 0)
312 continue;
313 memmove(buf, iov[i].iov_base, iov[i].iov_len);
314 buf += iov[i].iov_len;
317 return (0);
321 int
322 iobuf_fqueue(struct iobuf *io, const char *fmt, ...)
324 va_list ap;
325 int len;
327 va_start(ap, fmt);
328 len = iobuf_vfqueue(io, fmt, ap);
329 va_end(ap);
331 return (len);
334 int
335 iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap)
337 char *buf;
338 int len;
340 len = vasprintf(&buf, fmt, ap);
342 if (len == -1)
343 return (-1);
345 len = iobuf_queue(io, buf, len);
346 free(buf);
348 return (len);
351 ssize_t
352 iobuf_write(struct iobuf *io, int fd)
354 struct iovec iov[IOV_MAX];
355 struct ioqbuf *q;
356 int i;
357 ssize_t n;
359 i = 0;
360 for (q = io->outq; q ; q = q->next) {
361 if (i >= IOV_MAX)
362 break;
363 iov[i].iov_base = q->buf + q->rpos;
364 iov[i].iov_len = q->wpos - q->rpos;
365 i++;
368 n = writev(fd, iov, i);
369 if (n == -1) {
370 if (errno == EAGAIN || errno == EINTR)
371 return (IOBUF_WANT_WRITE);
372 if (errno == EPIPE)
373 return (IOBUF_CLOSED);
374 return (IOBUF_ERROR);
377 iobuf_drain(io, n);
379 return (n);
382 int
383 iobuf_flush(struct iobuf *io, int fd)
385 ssize_t s;
387 while (io->queued)
388 if ((s = iobuf_write(io, fd)) < 0)
389 return (s);
391 return (0);
394 #ifdef IO_TLS
396 int
397 iobuf_flush_tls(struct iobuf *io, void *tls)
399 ssize_t s;
401 while (io->queued)
402 if ((s = iobuf_write_tls(io, tls)) < 0)
403 return (s);
405 return (0);
408 ssize_t
409 iobuf_write_tls(struct iobuf *io, void *tls)
411 struct ioqbuf *q;
412 int r;
413 ssize_t n;
415 q = io->outq;
416 n = SSL_write(tls, q->buf + q->rpos, q->wpos - q->rpos);
417 if (n <= 0) {
418 switch ((r = SSL_get_error(tls, n))) {
419 case SSL_ERROR_WANT_READ:
420 return (IOBUF_WANT_READ);
421 case SSL_ERROR_WANT_WRITE:
422 return (IOBUF_WANT_WRITE);
423 case SSL_ERROR_ZERO_RETURN: /* connection closed */
424 return (IOBUF_CLOSED);
425 case SSL_ERROR_SYSCALL:
426 if (ERR_peek_last_error())
427 return (IOBUF_TLSERROR);
428 if (r == 0)
429 errno = EPIPE;
430 return (IOBUF_ERROR);
431 default:
432 return (IOBUF_TLSERROR);
435 iobuf_drain(io, n);
437 return (n);
440 ssize_t
441 iobuf_read_tls(struct iobuf *io, void *tls)
443 ssize_t n;
444 int r;
446 n = SSL_read(tls, io->buf + io->wpos, iobuf_left(io));
447 if (n < 0) {
448 switch ((r = SSL_get_error(tls, n))) {
449 case SSL_ERROR_WANT_READ:
450 return (IOBUF_WANT_READ);
451 case SSL_ERROR_WANT_WRITE:
452 return (IOBUF_WANT_WRITE);
453 case SSL_ERROR_SYSCALL:
454 if (ERR_peek_last_error())
455 return (IOBUF_TLSERROR);
456 if (r == 0)
457 errno = EPIPE;
458 return (IOBUF_ERROR);
459 default:
460 return (IOBUF_TLSERROR);
462 } else if (n == 0)
463 return (IOBUF_CLOSED);
465 io->wpos += n;
467 return (n);
470 #endif /* IO_TLS */