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