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