1*3b188dabSeric /* $OpenBSD: iobuf.c,v 1.1.1.1 2018/04/27 16:14:36 eric Exp $ */
2*3b188dabSeric
3*3b188dabSeric /*
4*3b188dabSeric * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
5*3b188dabSeric *
6*3b188dabSeric * Permission to use, copy, modify, and distribute this software for any
7*3b188dabSeric * purpose with or without fee is hereby granted, provided that the above
8*3b188dabSeric * copyright notice and this permission notice appear in all copies.
9*3b188dabSeric *
10*3b188dabSeric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*3b188dabSeric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*3b188dabSeric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*3b188dabSeric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*3b188dabSeric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*3b188dabSeric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*3b188dabSeric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*3b188dabSeric */
18*3b188dabSeric
19*3b188dabSeric #include <sys/types.h>
20*3b188dabSeric #include <sys/socket.h>
21*3b188dabSeric #include <sys/uio.h>
22*3b188dabSeric
23*3b188dabSeric #include <errno.h>
24*3b188dabSeric #include <limits.h>
25*3b188dabSeric #include <stdarg.h>
26*3b188dabSeric #include <stdio.h>
27*3b188dabSeric #include <stdlib.h>
28*3b188dabSeric #include <string.h>
29*3b188dabSeric #include <unistd.h>
30*3b188dabSeric
31*3b188dabSeric #ifdef IO_SSL
32*3b188dabSeric #include <openssl/err.h>
33*3b188dabSeric #include <openssl/ssl.h>
34*3b188dabSeric #endif
35*3b188dabSeric
36*3b188dabSeric #include "iobuf.h"
37*3b188dabSeric
38*3b188dabSeric #define IOBUF_MAX 65536
39*3b188dabSeric #define IOBUFQ_MIN 4096
40*3b188dabSeric
41*3b188dabSeric struct ioqbuf *ioqbuf_alloc(struct iobuf *, size_t);
42*3b188dabSeric void iobuf_drain(struct iobuf *, size_t);
43*3b188dabSeric
44*3b188dabSeric int
iobuf_init(struct iobuf * io,size_t size,size_t max)45*3b188dabSeric iobuf_init(struct iobuf *io, size_t size, size_t max)
46*3b188dabSeric {
47*3b188dabSeric memset(io, 0, sizeof *io);
48*3b188dabSeric
49*3b188dabSeric if (max == 0)
50*3b188dabSeric max = IOBUF_MAX;
51*3b188dabSeric
52*3b188dabSeric if (size == 0)
53*3b188dabSeric size = max;
54*3b188dabSeric
55*3b188dabSeric if (size > max)
56*3b188dabSeric return (-1);
57*3b188dabSeric
58*3b188dabSeric if ((io->buf = calloc(size, 1)) == NULL)
59*3b188dabSeric return (-1);
60*3b188dabSeric
61*3b188dabSeric io->size = size;
62*3b188dabSeric io->max = max;
63*3b188dabSeric
64*3b188dabSeric return (0);
65*3b188dabSeric }
66*3b188dabSeric
67*3b188dabSeric void
iobuf_clear(struct iobuf * io)68*3b188dabSeric iobuf_clear(struct iobuf *io)
69*3b188dabSeric {
70*3b188dabSeric struct ioqbuf *q;
71*3b188dabSeric
72*3b188dabSeric free(io->buf);
73*3b188dabSeric
74*3b188dabSeric while ((q = io->outq)) {
75*3b188dabSeric io->outq = q->next;
76*3b188dabSeric free(q);
77*3b188dabSeric }
78*3b188dabSeric
79*3b188dabSeric memset(io, 0, sizeof (*io));
80*3b188dabSeric }
81*3b188dabSeric
82*3b188dabSeric void
iobuf_drain(struct iobuf * io,size_t n)83*3b188dabSeric iobuf_drain(struct iobuf *io, size_t n)
84*3b188dabSeric {
85*3b188dabSeric struct ioqbuf *q;
86*3b188dabSeric size_t left = n;
87*3b188dabSeric
88*3b188dabSeric while ((q = io->outq) && left) {
89*3b188dabSeric if ((q->wpos - q->rpos) > left) {
90*3b188dabSeric q->rpos += left;
91*3b188dabSeric left = 0;
92*3b188dabSeric } else {
93*3b188dabSeric left -= q->wpos - q->rpos;
94*3b188dabSeric io->outq = q->next;
95*3b188dabSeric free(q);
96*3b188dabSeric }
97*3b188dabSeric }
98*3b188dabSeric
99*3b188dabSeric io->queued -= (n - left);
100*3b188dabSeric if (io->outq == NULL)
101*3b188dabSeric io->outqlast = NULL;
102*3b188dabSeric }
103*3b188dabSeric
104*3b188dabSeric int
iobuf_extend(struct iobuf * io,size_t n)105*3b188dabSeric iobuf_extend(struct iobuf *io, size_t n)
106*3b188dabSeric {
107*3b188dabSeric char *t;
108*3b188dabSeric
109*3b188dabSeric if (n > io->max)
110*3b188dabSeric return (-1);
111*3b188dabSeric
112*3b188dabSeric if (io->max - io->size < n)
113*3b188dabSeric return (-1);
114*3b188dabSeric
115*3b188dabSeric t = recallocarray(io->buf, io->size, io->size + n, 1);
116*3b188dabSeric if (t == NULL)
117*3b188dabSeric return (-1);
118*3b188dabSeric
119*3b188dabSeric io->size += n;
120*3b188dabSeric io->buf = t;
121*3b188dabSeric
122*3b188dabSeric return (0);
123*3b188dabSeric }
124*3b188dabSeric
125*3b188dabSeric size_t
iobuf_left(struct iobuf * io)126*3b188dabSeric iobuf_left(struct iobuf *io)
127*3b188dabSeric {
128*3b188dabSeric return io->size - io->wpos;
129*3b188dabSeric }
130*3b188dabSeric
131*3b188dabSeric size_t
iobuf_space(struct iobuf * io)132*3b188dabSeric iobuf_space(struct iobuf *io)
133*3b188dabSeric {
134*3b188dabSeric return io->size - (io->wpos - io->rpos);
135*3b188dabSeric }
136*3b188dabSeric
137*3b188dabSeric size_t
iobuf_len(struct iobuf * io)138*3b188dabSeric iobuf_len(struct iobuf *io)
139*3b188dabSeric {
140*3b188dabSeric return io->wpos - io->rpos;
141*3b188dabSeric }
142*3b188dabSeric
143*3b188dabSeric char *
iobuf_data(struct iobuf * io)144*3b188dabSeric iobuf_data(struct iobuf *io)
145*3b188dabSeric {
146*3b188dabSeric return io->buf + io->rpos;
147*3b188dabSeric }
148*3b188dabSeric
149*3b188dabSeric void
iobuf_drop(struct iobuf * io,size_t n)150*3b188dabSeric iobuf_drop(struct iobuf *io, size_t n)
151*3b188dabSeric {
152*3b188dabSeric if (n >= iobuf_len(io)) {
153*3b188dabSeric io->rpos = io->wpos = 0;
154*3b188dabSeric return;
155*3b188dabSeric }
156*3b188dabSeric
157*3b188dabSeric io->rpos += n;
158*3b188dabSeric }
159*3b188dabSeric
160*3b188dabSeric char *
iobuf_getline(struct iobuf * iobuf,size_t * rlen)161*3b188dabSeric iobuf_getline(struct iobuf *iobuf, size_t *rlen)
162*3b188dabSeric {
163*3b188dabSeric char *buf;
164*3b188dabSeric size_t len, i;
165*3b188dabSeric
166*3b188dabSeric buf = iobuf_data(iobuf);
167*3b188dabSeric len = iobuf_len(iobuf);
168*3b188dabSeric
169*3b188dabSeric for (i = 0; i + 1 <= len; i++)
170*3b188dabSeric if (buf[i] == '\n') {
171*3b188dabSeric /* Note: the returned address points into the iobuf
172*3b188dabSeric * buffer. We NUL-end it for convenience, and discard
173*3b188dabSeric * the data from the iobuf, so that the caller doesn't
174*3b188dabSeric * have to do it. The data remains "valid" as long
175*3b188dabSeric * as the iobuf does not overwrite it, that is until
176*3b188dabSeric * the next call to iobuf_normalize() or iobuf_extend().
177*3b188dabSeric */
178*3b188dabSeric iobuf_drop(iobuf, i + 1);
179*3b188dabSeric len = (i && buf[i - 1] == '\r') ? i - 1 : i;
180*3b188dabSeric buf[len] = '\0';
181*3b188dabSeric if (rlen)
182*3b188dabSeric *rlen = len;
183*3b188dabSeric return (buf);
184*3b188dabSeric }
185*3b188dabSeric
186*3b188dabSeric return (NULL);
187*3b188dabSeric }
188*3b188dabSeric
189*3b188dabSeric void
iobuf_normalize(struct iobuf * io)190*3b188dabSeric iobuf_normalize(struct iobuf *io)
191*3b188dabSeric {
192*3b188dabSeric if (io->rpos == 0)
193*3b188dabSeric return;
194*3b188dabSeric
195*3b188dabSeric if (io->rpos == io->wpos) {
196*3b188dabSeric io->rpos = io->wpos = 0;
197*3b188dabSeric return;
198*3b188dabSeric }
199*3b188dabSeric
200*3b188dabSeric memmove(io->buf, io->buf + io->rpos, io->wpos - io->rpos);
201*3b188dabSeric io->wpos -= io->rpos;
202*3b188dabSeric io->rpos = 0;
203*3b188dabSeric }
204*3b188dabSeric
205*3b188dabSeric ssize_t
iobuf_read(struct iobuf * io,int fd)206*3b188dabSeric iobuf_read(struct iobuf *io, int fd)
207*3b188dabSeric {
208*3b188dabSeric ssize_t n;
209*3b188dabSeric
210*3b188dabSeric n = read(fd, io->buf + io->wpos, iobuf_left(io));
211*3b188dabSeric if (n == -1) {
212*3b188dabSeric /* XXX is this really what we want? */
213*3b188dabSeric if (errno == EAGAIN || errno == EINTR)
214*3b188dabSeric return (IOBUF_WANT_READ);
215*3b188dabSeric return (IOBUF_ERROR);
216*3b188dabSeric }
217*3b188dabSeric if (n == 0)
218*3b188dabSeric return (IOBUF_CLOSED);
219*3b188dabSeric
220*3b188dabSeric io->wpos += n;
221*3b188dabSeric
222*3b188dabSeric return (n);
223*3b188dabSeric }
224*3b188dabSeric
225*3b188dabSeric struct ioqbuf *
ioqbuf_alloc(struct iobuf * io,size_t len)226*3b188dabSeric ioqbuf_alloc(struct iobuf *io, size_t len)
227*3b188dabSeric {
228*3b188dabSeric struct ioqbuf *q;
229*3b188dabSeric
230*3b188dabSeric if (len < IOBUFQ_MIN)
231*3b188dabSeric len = IOBUFQ_MIN;
232*3b188dabSeric
233*3b188dabSeric if ((q = malloc(sizeof(*q) + len)) == NULL)
234*3b188dabSeric return (NULL);
235*3b188dabSeric
236*3b188dabSeric q->rpos = 0;
237*3b188dabSeric q->wpos = 0;
238*3b188dabSeric q->size = len;
239*3b188dabSeric q->next = NULL;
240*3b188dabSeric q->buf = (char *)(q) + sizeof(*q);
241*3b188dabSeric
242*3b188dabSeric if (io->outqlast == NULL)
243*3b188dabSeric io->outq = q;
244*3b188dabSeric else
245*3b188dabSeric io->outqlast->next = q;
246*3b188dabSeric io->outqlast = q;
247*3b188dabSeric
248*3b188dabSeric return (q);
249*3b188dabSeric }
250*3b188dabSeric
251*3b188dabSeric size_t
iobuf_queued(struct iobuf * io)252*3b188dabSeric iobuf_queued(struct iobuf *io)
253*3b188dabSeric {
254*3b188dabSeric return io->queued;
255*3b188dabSeric }
256*3b188dabSeric
257*3b188dabSeric void *
iobuf_reserve(struct iobuf * io,size_t len)258*3b188dabSeric iobuf_reserve(struct iobuf *io, size_t len)
259*3b188dabSeric {
260*3b188dabSeric struct ioqbuf *q;
261*3b188dabSeric void *r;
262*3b188dabSeric
263*3b188dabSeric if (len == 0)
264*3b188dabSeric return (NULL);
265*3b188dabSeric
266*3b188dabSeric if (((q = io->outqlast) == NULL) || q->size - q->wpos <= len) {
267*3b188dabSeric if ((q = ioqbuf_alloc(io, len)) == NULL)
268*3b188dabSeric return (NULL);
269*3b188dabSeric }
270*3b188dabSeric
271*3b188dabSeric r = q->buf + q->wpos;
272*3b188dabSeric q->wpos += len;
273*3b188dabSeric io->queued += len;
274*3b188dabSeric
275*3b188dabSeric return (r);
276*3b188dabSeric }
277*3b188dabSeric
278*3b188dabSeric int
iobuf_queue(struct iobuf * io,const void * data,size_t len)279*3b188dabSeric iobuf_queue(struct iobuf *io, const void *data, size_t len)
280*3b188dabSeric {
281*3b188dabSeric void *buf;
282*3b188dabSeric
283*3b188dabSeric if (len == 0)
284*3b188dabSeric return (0);
285*3b188dabSeric
286*3b188dabSeric if ((buf = iobuf_reserve(io, len)) == NULL)
287*3b188dabSeric return (-1);
288*3b188dabSeric
289*3b188dabSeric memmove(buf, data, len);
290*3b188dabSeric
291*3b188dabSeric return (len);
292*3b188dabSeric }
293*3b188dabSeric
294*3b188dabSeric int
iobuf_queuev(struct iobuf * io,const struct iovec * iov,int iovcnt)295*3b188dabSeric iobuf_queuev(struct iobuf *io, const struct iovec *iov, int iovcnt)
296*3b188dabSeric {
297*3b188dabSeric int i;
298*3b188dabSeric size_t len = 0;
299*3b188dabSeric char *buf;
300*3b188dabSeric
301*3b188dabSeric for (i = 0; i < iovcnt; i++)
302*3b188dabSeric len += iov[i].iov_len;
303*3b188dabSeric
304*3b188dabSeric if ((buf = iobuf_reserve(io, len)) == NULL)
305*3b188dabSeric return (-1);
306*3b188dabSeric
307*3b188dabSeric for (i = 0; i < iovcnt; i++) {
308*3b188dabSeric if (iov[i].iov_len == 0)
309*3b188dabSeric continue;
310*3b188dabSeric memmove(buf, iov[i].iov_base, iov[i].iov_len);
311*3b188dabSeric buf += iov[i].iov_len;
312*3b188dabSeric }
313*3b188dabSeric
314*3b188dabSeric return (0);
315*3b188dabSeric
316*3b188dabSeric }
317*3b188dabSeric
318*3b188dabSeric int
iobuf_fqueue(struct iobuf * io,const char * fmt,...)319*3b188dabSeric iobuf_fqueue(struct iobuf *io, const char *fmt, ...)
320*3b188dabSeric {
321*3b188dabSeric va_list ap;
322*3b188dabSeric int len;
323*3b188dabSeric
324*3b188dabSeric va_start(ap, fmt);
325*3b188dabSeric len = iobuf_vfqueue(io, fmt, ap);
326*3b188dabSeric va_end(ap);
327*3b188dabSeric
328*3b188dabSeric return (len);
329*3b188dabSeric }
330*3b188dabSeric
331*3b188dabSeric int
iobuf_vfqueue(struct iobuf * io,const char * fmt,va_list ap)332*3b188dabSeric iobuf_vfqueue(struct iobuf *io, const char *fmt, va_list ap)
333*3b188dabSeric {
334*3b188dabSeric char *buf;
335*3b188dabSeric int len;
336*3b188dabSeric
337*3b188dabSeric len = vasprintf(&buf, fmt, ap);
338*3b188dabSeric
339*3b188dabSeric if (len == -1)
340*3b188dabSeric return (-1);
341*3b188dabSeric
342*3b188dabSeric len = iobuf_queue(io, buf, len);
343*3b188dabSeric free(buf);
344*3b188dabSeric
345*3b188dabSeric return (len);
346*3b188dabSeric }
347*3b188dabSeric
348*3b188dabSeric ssize_t
iobuf_write(struct iobuf * io,int fd)349*3b188dabSeric iobuf_write(struct iobuf *io, int fd)
350*3b188dabSeric {
351*3b188dabSeric struct iovec iov[IOV_MAX];
352*3b188dabSeric struct ioqbuf *q;
353*3b188dabSeric int i;
354*3b188dabSeric ssize_t n;
355*3b188dabSeric
356*3b188dabSeric i = 0;
357*3b188dabSeric for (q = io->outq; q ; q = q->next) {
358*3b188dabSeric if (i >= IOV_MAX)
359*3b188dabSeric break;
360*3b188dabSeric iov[i].iov_base = q->buf + q->rpos;
361*3b188dabSeric iov[i].iov_len = q->wpos - q->rpos;
362*3b188dabSeric i++;
363*3b188dabSeric }
364*3b188dabSeric
365*3b188dabSeric n = writev(fd, iov, i);
366*3b188dabSeric if (n == -1) {
367*3b188dabSeric if (errno == EAGAIN || errno == EINTR)
368*3b188dabSeric return (IOBUF_WANT_WRITE);
369*3b188dabSeric if (errno == EPIPE)
370*3b188dabSeric return (IOBUF_CLOSED);
371*3b188dabSeric return (IOBUF_ERROR);
372*3b188dabSeric }
373*3b188dabSeric
374*3b188dabSeric iobuf_drain(io, n);
375*3b188dabSeric
376*3b188dabSeric return (n);
377*3b188dabSeric }
378*3b188dabSeric
379*3b188dabSeric int
iobuf_flush(struct iobuf * io,int fd)380*3b188dabSeric iobuf_flush(struct iobuf *io, int fd)
381*3b188dabSeric {
382*3b188dabSeric ssize_t s;
383*3b188dabSeric
384*3b188dabSeric while (io->queued)
385*3b188dabSeric if ((s = iobuf_write(io, fd)) < 0)
386*3b188dabSeric return (s);
387*3b188dabSeric
388*3b188dabSeric return (0);
389*3b188dabSeric }
390*3b188dabSeric
391*3b188dabSeric #ifdef IO_SSL
392*3b188dabSeric
393*3b188dabSeric int
iobuf_flush_ssl(struct iobuf * io,void * ssl)394*3b188dabSeric iobuf_flush_ssl(struct iobuf *io, void *ssl)
395*3b188dabSeric {
396*3b188dabSeric ssize_t s;
397*3b188dabSeric
398*3b188dabSeric while (io->queued)
399*3b188dabSeric if ((s = iobuf_write_ssl(io, ssl)) < 0)
400*3b188dabSeric return (s);
401*3b188dabSeric
402*3b188dabSeric return (0);
403*3b188dabSeric }
404*3b188dabSeric
405*3b188dabSeric ssize_t
iobuf_write_ssl(struct iobuf * io,void * ssl)406*3b188dabSeric iobuf_write_ssl(struct iobuf *io, void *ssl)
407*3b188dabSeric {
408*3b188dabSeric struct ioqbuf *q;
409*3b188dabSeric int r;
410*3b188dabSeric ssize_t n;
411*3b188dabSeric
412*3b188dabSeric q = io->outq;
413*3b188dabSeric n = SSL_write(ssl, q->buf + q->rpos, q->wpos - q->rpos);
414*3b188dabSeric if (n <= 0) {
415*3b188dabSeric switch ((r = SSL_get_error(ssl, n))) {
416*3b188dabSeric case SSL_ERROR_WANT_READ:
417*3b188dabSeric return (IOBUF_WANT_READ);
418*3b188dabSeric case SSL_ERROR_WANT_WRITE:
419*3b188dabSeric return (IOBUF_WANT_WRITE);
420*3b188dabSeric case SSL_ERROR_ZERO_RETURN: /* connection closed */
421*3b188dabSeric return (IOBUF_CLOSED);
422*3b188dabSeric case SSL_ERROR_SYSCALL:
423*3b188dabSeric if (ERR_peek_last_error())
424*3b188dabSeric return (IOBUF_SSLERROR);
425*3b188dabSeric if (r == 0)
426*3b188dabSeric errno = EPIPE;
427*3b188dabSeric return (IOBUF_ERROR);
428*3b188dabSeric default:
429*3b188dabSeric return (IOBUF_SSLERROR);
430*3b188dabSeric }
431*3b188dabSeric }
432*3b188dabSeric iobuf_drain(io, n);
433*3b188dabSeric
434*3b188dabSeric return (n);
435*3b188dabSeric }
436*3b188dabSeric
437*3b188dabSeric ssize_t
iobuf_read_ssl(struct iobuf * io,void * ssl)438*3b188dabSeric iobuf_read_ssl(struct iobuf *io, void *ssl)
439*3b188dabSeric {
440*3b188dabSeric ssize_t n;
441*3b188dabSeric int r;
442*3b188dabSeric
443*3b188dabSeric n = SSL_read(ssl, io->buf + io->wpos, iobuf_left(io));
444*3b188dabSeric if (n < 0) {
445*3b188dabSeric switch ((r = SSL_get_error(ssl, n))) {
446*3b188dabSeric case SSL_ERROR_WANT_READ:
447*3b188dabSeric return (IOBUF_WANT_READ);
448*3b188dabSeric case SSL_ERROR_WANT_WRITE:
449*3b188dabSeric return (IOBUF_WANT_WRITE);
450*3b188dabSeric case SSL_ERROR_SYSCALL:
451*3b188dabSeric if (ERR_peek_last_error())
452*3b188dabSeric return (IOBUF_SSLERROR);
453*3b188dabSeric if (r == 0)
454*3b188dabSeric errno = EPIPE;
455*3b188dabSeric return (IOBUF_ERROR);
456*3b188dabSeric default:
457*3b188dabSeric return (IOBUF_SSLERROR);
458*3b188dabSeric }
459*3b188dabSeric } else if (n == 0)
460*3b188dabSeric return (IOBUF_CLOSED);
461*3b188dabSeric
462*3b188dabSeric io->wpos += n;
463*3b188dabSeric
464*3b188dabSeric return (n);
465*3b188dabSeric }
466*3b188dabSeric
467*3b188dabSeric #endif /* IO_SSL */
468