GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../iobuf.c Lines: 0 175 0.0 %
Date: 2017-11-07 Branches: 0 115 0.0 %

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