1171169Smlaier/*
2171169Smlaier * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
3171169Smlaier * All rights reserved.
4171169Smlaier *
5171169Smlaier * Redistribution and use in source and binary forms, with or without
6171169Smlaier * modification, are permitted provided that the following conditions
7171169Smlaier * are met:
8171169Smlaier * 1. Redistributions of source code must retain the above copyright
9171169Smlaier *    notice, this list of conditions and the following disclaimer.
10171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright
11171169Smlaier *    notice, this list of conditions and the following disclaimer in the
12171169Smlaier *    documentation and/or other materials provided with the distribution.
13171169Smlaier * 3. The name of the author may not be used to endorse or promote products
14171169Smlaier *    derived from this software without specific prior written permission.
15171169Smlaier *
16171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26171169Smlaier */
27171169Smlaier
28171169Smlaier#ifdef HAVE_CONFIG_H
29171169Smlaier#include "config.h"
30171169Smlaier#endif
31171169Smlaier
32171169Smlaier#ifdef HAVE_VASPRINTF
33171169Smlaier/* If we have vasprintf, we need to define this before we include stdio.h. */
34171169Smlaier#define _GNU_SOURCE
35171169Smlaier#endif
36171169Smlaier
37171169Smlaier#include <sys/types.h>
38171169Smlaier
39171169Smlaier#ifdef HAVE_SYS_TIME_H
40171169Smlaier#include <sys/time.h>
41171169Smlaier#endif
42171169Smlaier
43171169Smlaier#ifdef HAVE_SYS_IOCTL_H
44171169Smlaier#include <sys/ioctl.h>
45171169Smlaier#endif
46171169Smlaier
47171169Smlaier#include <errno.h>
48171169Smlaier#include <stdio.h>
49171169Smlaier#include <stdlib.h>
50171169Smlaier#include <string.h>
51171169Smlaier#ifdef HAVE_STDARG_H
52171169Smlaier#include <stdarg.h>
53171169Smlaier#endif
54171169Smlaier#ifdef HAVE_UNISTD_H
55171169Smlaier#include <unistd.h>
56171169Smlaier#endif
57171169Smlaier
58171169Smlaier#include "event.h"
59171169Smlaier
60171169Smlaierstruct evbuffer *
61171169Smlaierevbuffer_new(void)
62171169Smlaier{
63171169Smlaier	struct evbuffer *buffer;
64171169Smlaier
65171169Smlaier	buffer = calloc(1, sizeof(struct evbuffer));
66171169Smlaier
67171169Smlaier	return (buffer);
68171169Smlaier}
69171169Smlaier
70171169Smlaiervoid
71171169Smlaierevbuffer_free(struct evbuffer *buffer)
72171169Smlaier{
73171169Smlaier	if (buffer->orig_buffer != NULL)
74171169Smlaier		free(buffer->orig_buffer);
75171169Smlaier	free(buffer);
76171169Smlaier}
77171169Smlaier
78171169Smlaier/*
79171169Smlaier * This is a destructive add.  The data from one buffer moves into
80171169Smlaier * the other buffer.
81171169Smlaier */
82171169Smlaier
83171169Smlaier#define SWAP(x,y) do { \
84171169Smlaier	(x)->buffer = (y)->buffer; \
85171169Smlaier	(x)->orig_buffer = (y)->orig_buffer; \
86171169Smlaier	(x)->misalign = (y)->misalign; \
87171169Smlaier	(x)->totallen = (y)->totallen; \
88171169Smlaier	(x)->off = (y)->off; \
89171169Smlaier} while (0)
90171169Smlaier
91171169Smlaierint
92171169Smlaierevbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
93171169Smlaier{
94171169Smlaier	int res;
95171169Smlaier
96171169Smlaier	/* Short cut for better performance */
97171169Smlaier	if (outbuf->off == 0) {
98171169Smlaier		struct evbuffer tmp;
99171169Smlaier		size_t oldoff = inbuf->off;
100171169Smlaier
101171169Smlaier		/* Swap them directly */
102171169Smlaier		SWAP(&tmp, outbuf);
103171169Smlaier		SWAP(outbuf, inbuf);
104171169Smlaier		SWAP(inbuf, &tmp);
105171169Smlaier
106171169Smlaier		/*
107171169Smlaier		 * Optimization comes with a price; we need to notify the
108171169Smlaier		 * buffer if necessary of the changes. oldoff is the amount
109171169Smlaier		 * of data that we tranfered from inbuf to outbuf
110171169Smlaier		 */
111171169Smlaier		if (inbuf->off != oldoff && inbuf->cb != NULL)
112171169Smlaier			(*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
113171169Smlaier		if (oldoff && outbuf->cb != NULL)
114171169Smlaier			(*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
115171169Smlaier
116171169Smlaier		return (0);
117171169Smlaier	}
118171169Smlaier
119171169Smlaier	res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
120171169Smlaier	if (res == 0) {
121171169Smlaier		/* We drain the input buffer on success */
122171169Smlaier		evbuffer_drain(inbuf, inbuf->off);
123171169Smlaier	}
124171169Smlaier
125171169Smlaier	return (res);
126171169Smlaier}
127171169Smlaier
128171169Smlaierint
129171169Smlaierevbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
130171169Smlaier{
131171169Smlaier	char *buffer;
132171169Smlaier	size_t space;
133171169Smlaier	size_t oldoff = buf->off;
134171169Smlaier	int sz;
135171169Smlaier	va_list aq;
136171169Smlaier
137171169Smlaier	for (;;) {
138171169Smlaier		buffer = (char *)buf->buffer + buf->off;
139171169Smlaier		space = buf->totallen - buf->misalign - buf->off;
140171169Smlaier
141171169Smlaier#ifndef va_copy
142171169Smlaier#define	va_copy(dst, src)	memcpy(&(dst), &(src), sizeof(va_list))
143171169Smlaier#endif
144171169Smlaier		va_copy(aq, ap);
145171169Smlaier
146171169Smlaier#ifdef WIN32
147171169Smlaier		sz = vsnprintf(buffer, space - 1, fmt, aq);
148171169Smlaier		buffer[space - 1] = '\0';
149171169Smlaier#else
150171169Smlaier		sz = vsnprintf(buffer, space, fmt, aq);
151171169Smlaier#endif
152171169Smlaier
153171169Smlaier		va_end(aq);
154171169Smlaier
155171169Smlaier		if (sz == -1)
156171169Smlaier			return (-1);
157171169Smlaier		if (sz < space) {
158171169Smlaier			buf->off += sz;
159171169Smlaier			if (buf->cb != NULL)
160171169Smlaier				(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
161171169Smlaier			return (sz);
162171169Smlaier		}
163171169Smlaier		if (evbuffer_expand(buf, sz + 1) == -1)
164171169Smlaier			return (-1);
165171169Smlaier
166171169Smlaier	}
167171169Smlaier	/* NOTREACHED */
168171169Smlaier}
169171169Smlaier
170171169Smlaierint
171171169Smlaierevbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
172171169Smlaier{
173171169Smlaier	int res = -1;
174171169Smlaier	va_list ap;
175171169Smlaier
176171169Smlaier	va_start(ap, fmt);
177171169Smlaier	res = evbuffer_add_vprintf(buf, fmt, ap);
178171169Smlaier	va_end(ap);
179171169Smlaier
180171169Smlaier	return (res);
181171169Smlaier}
182171169Smlaier
183171169Smlaier/* Reads data from an event buffer and drains the bytes read */
184171169Smlaier
185171169Smlaierint
186171169Smlaierevbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
187171169Smlaier{
188171169Smlaier	size_t nread = datlen;
189171169Smlaier	if (nread >= buf->off)
190171169Smlaier		nread = buf->off;
191171169Smlaier
192171169Smlaier	memcpy(data, buf->buffer, nread);
193171169Smlaier	evbuffer_drain(buf, nread);
194171169Smlaier
195171169Smlaier	return (nread);
196171169Smlaier}
197171169Smlaier
198171169Smlaier/*
199171169Smlaier * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
200171169Smlaier * The returned buffer needs to be freed by the called.
201171169Smlaier */
202171169Smlaier
203171169Smlaierchar *
204171169Smlaierevbuffer_readline(struct evbuffer *buffer)
205171169Smlaier{
206171169Smlaier	u_char *data = EVBUFFER_DATA(buffer);
207171169Smlaier	size_t len = EVBUFFER_LENGTH(buffer);
208171169Smlaier	char *line;
209171169Smlaier	unsigned int i;
210171169Smlaier
211171169Smlaier	for (i = 0; i < len; i++) {
212171169Smlaier		if (data[i] == '\r' || data[i] == '\n')
213171169Smlaier			break;
214171169Smlaier	}
215171169Smlaier
216171169Smlaier	if (i == len)
217171169Smlaier		return (NULL);
218171169Smlaier
219171169Smlaier	if ((line = malloc(i + 1)) == NULL) {
220171169Smlaier		fprintf(stderr, "%s: out of memory\n", __func__);
221171169Smlaier		evbuffer_drain(buffer, i);
222171169Smlaier		return (NULL);
223171169Smlaier	}
224171169Smlaier
225171169Smlaier	memcpy(line, data, i);
226171169Smlaier	line[i] = '\0';
227171169Smlaier
228171169Smlaier	/*
229171169Smlaier	 * Some protocols terminate a line with '\r\n', so check for
230171169Smlaier	 * that, too.
231171169Smlaier	 */
232171169Smlaier	if ( i < len - 1 ) {
233171169Smlaier		char fch = data[i], sch = data[i+1];
234171169Smlaier
235171169Smlaier		/* Drain one more character if needed */
236171169Smlaier		if ( (sch == '\r' || sch == '\n') && sch != fch )
237171169Smlaier			i += 1;
238171169Smlaier	}
239171169Smlaier
240171169Smlaier	evbuffer_drain(buffer, i + 1);
241171169Smlaier
242171169Smlaier	return (line);
243171169Smlaier}
244171169Smlaier
245171169Smlaier/* Adds data to an event buffer */
246171169Smlaier
247171169Smlaierstatic inline void
248171169Smlaierevbuffer_align(struct evbuffer *buf)
249171169Smlaier{
250171169Smlaier	memmove(buf->orig_buffer, buf->buffer, buf->off);
251171169Smlaier	buf->buffer = buf->orig_buffer;
252171169Smlaier	buf->misalign = 0;
253171169Smlaier}
254171169Smlaier
255171169Smlaier/* Expands the available space in the event buffer to at least datlen */
256171169Smlaier
257171169Smlaierint
258171169Smlaierevbuffer_expand(struct evbuffer *buf, size_t datlen)
259171169Smlaier{
260171169Smlaier	size_t need = buf->misalign + buf->off + datlen;
261171169Smlaier
262171169Smlaier	/* If we can fit all the data, then we don't have to do anything */
263171169Smlaier	if (buf->totallen >= need)
264171169Smlaier		return (0);
265171169Smlaier
266171169Smlaier	/*
267171169Smlaier	 * If the misalignment fulfills our data needs, we just force an
268171169Smlaier	 * alignment to happen.  Afterwards, we have enough space.
269171169Smlaier	 */
270171169Smlaier	if (buf->misalign >= datlen) {
271171169Smlaier		evbuffer_align(buf);
272171169Smlaier	} else {
273171169Smlaier		void *newbuf;
274171169Smlaier		size_t length = buf->totallen;
275171169Smlaier
276171169Smlaier		if (length < 256)
277171169Smlaier			length = 256;
278171169Smlaier		while (length < need)
279171169Smlaier			length <<= 1;
280171169Smlaier
281171169Smlaier		if (buf->orig_buffer != buf->buffer)
282171169Smlaier			evbuffer_align(buf);
283171169Smlaier		if ((newbuf = realloc(buf->buffer, length)) == NULL)
284171169Smlaier			return (-1);
285171169Smlaier
286171169Smlaier		buf->orig_buffer = buf->buffer = newbuf;
287171169Smlaier		buf->totallen = length;
288171169Smlaier	}
289171169Smlaier
290171169Smlaier	return (0);
291171169Smlaier}
292171169Smlaier
293171169Smlaierint
294171169Smlaierevbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
295171169Smlaier{
296171169Smlaier	size_t need = buf->misalign + buf->off + datlen;
297171169Smlaier	size_t oldoff = buf->off;
298171169Smlaier
299171169Smlaier	if (buf->totallen < need) {
300171169Smlaier		if (evbuffer_expand(buf, datlen) == -1)
301171169Smlaier			return (-1);
302171169Smlaier	}
303171169Smlaier
304171169Smlaier	memcpy(buf->buffer + buf->off, data, datlen);
305171169Smlaier	buf->off += datlen;
306171169Smlaier
307171169Smlaier	if (datlen && buf->cb != NULL)
308171169Smlaier		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
309171169Smlaier
310171169Smlaier	return (0);
311171169Smlaier}
312171169Smlaier
313171169Smlaiervoid
314171169Smlaierevbuffer_drain(struct evbuffer *buf, size_t len)
315171169Smlaier{
316171169Smlaier	size_t oldoff = buf->off;
317171169Smlaier
318171169Smlaier	if (len >= buf->off) {
319171169Smlaier		buf->off = 0;
320171169Smlaier		buf->buffer = buf->orig_buffer;
321171169Smlaier		buf->misalign = 0;
322171169Smlaier		goto done;
323171169Smlaier	}
324171169Smlaier
325171169Smlaier	buf->buffer += len;
326171169Smlaier	buf->misalign += len;
327171169Smlaier
328171169Smlaier	buf->off -= len;
329171169Smlaier
330171169Smlaier done:
331171169Smlaier	/* Tell someone about changes in this buffer */
332171169Smlaier	if (buf->off != oldoff && buf->cb != NULL)
333171169Smlaier		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
334171169Smlaier
335171169Smlaier}
336171169Smlaier
337171169Smlaier/*
338171169Smlaier * Reads data from a file descriptor into a buffer.
339171169Smlaier */
340171169Smlaier
341171169Smlaier#define EVBUFFER_MAX_READ	4096
342171169Smlaier
343171169Smlaierint
344171169Smlaierevbuffer_read(struct evbuffer *buf, int fd, int howmuch)
345171169Smlaier{
346171169Smlaier	u_char *p;
347171169Smlaier	size_t oldoff = buf->off;
348171169Smlaier	int n = EVBUFFER_MAX_READ;
349171169Smlaier#ifdef WIN32
350171169Smlaier	DWORD dwBytesRead;
351171169Smlaier#endif
352171169Smlaier
353171169Smlaier#ifdef FIONREAD
354171169Smlaier	if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
355171169Smlaier		n = EVBUFFER_MAX_READ;
356171169Smlaier	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
357171169Smlaier		/*
358171169Smlaier		 * It's possible that a lot of data is available for
359171169Smlaier		 * reading.  We do not want to exhaust resources
360171169Smlaier		 * before the reader has a chance to do something
361171169Smlaier		 * about it.  If the reader does not tell us how much
362171169Smlaier		 * data we should read, we artifically limit it.
363171169Smlaier		 */
364171169Smlaier		if (n > buf->totallen << 2)
365171169Smlaier			n = buf->totallen << 2;
366171169Smlaier		if (n < EVBUFFER_MAX_READ)
367171169Smlaier			n = EVBUFFER_MAX_READ;
368171169Smlaier	}
369171169Smlaier#endif
370171169Smlaier	if (howmuch < 0 || howmuch > n)
371171169Smlaier		howmuch = n;
372171169Smlaier
373171169Smlaier	/* If we don't have FIONREAD, we might waste some space here */
374171169Smlaier	if (evbuffer_expand(buf, howmuch) == -1)
375171169Smlaier		return (-1);
376171169Smlaier
377171169Smlaier	/* We can append new data at this point */
378171169Smlaier	p = buf->buffer + buf->off;
379171169Smlaier
380171169Smlaier#ifndef WIN32
381171169Smlaier	n = read(fd, p, howmuch);
382171169Smlaier	if (n == -1)
383171169Smlaier		return (-1);
384171169Smlaier	if (n == 0)
385171169Smlaier		return (0);
386171169Smlaier#else
387171169Smlaier	n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL);
388171169Smlaier	if (n == 0)
389171169Smlaier		return (-1);
390171169Smlaier	if (dwBytesRead == 0)
391171169Smlaier		return (0);
392171169Smlaier	n = dwBytesRead;
393171169Smlaier#endif
394171169Smlaier
395171169Smlaier	buf->off += n;
396171169Smlaier
397171169Smlaier	/* Tell someone about changes in this buffer */
398171169Smlaier	if (buf->off != oldoff && buf->cb != NULL)
399171169Smlaier		(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
400171169Smlaier
401171169Smlaier	return (n);
402171169Smlaier}
403171169Smlaier
404171169Smlaierint
405171169Smlaierevbuffer_write(struct evbuffer *buffer, int fd)
406171169Smlaier{
407171169Smlaier	int n;
408171169Smlaier#ifdef WIN32
409171169Smlaier	DWORD dwBytesWritten;
410171169Smlaier#endif
411171169Smlaier
412171169Smlaier#ifndef WIN32
413171169Smlaier	n = write(fd, buffer->buffer, buffer->off);
414171169Smlaier	if (n == -1)
415171169Smlaier		return (-1);
416171169Smlaier	if (n == 0)
417171169Smlaier		return (0);
418171169Smlaier#else
419171169Smlaier	n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL);
420171169Smlaier	if (n == 0)
421171169Smlaier		return (-1);
422171169Smlaier	if (dwBytesWritten == 0)
423171169Smlaier		return (0);
424171169Smlaier	n = dwBytesWritten;
425171169Smlaier#endif
426171169Smlaier	evbuffer_drain(buffer, n);
427171169Smlaier
428171169Smlaier	return (n);
429171169Smlaier}
430171169Smlaier
431171169Smlaieru_char *
432171169Smlaierevbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
433171169Smlaier{
434171169Smlaier	size_t remain = buffer->off;
435171169Smlaier	u_char *search = buffer->buffer;
436171169Smlaier	u_char *p;
437171169Smlaier
438171169Smlaier	while ((p = memchr(search, *what, remain)) != NULL) {
439171169Smlaier		remain = buffer->off - (size_t)(search - buffer->buffer);
440171169Smlaier		if (remain < len)
441171169Smlaier			break;
442171169Smlaier		if (memcmp(p, what, len) == 0)
443171169Smlaier			return (p);
444171169Smlaier		search = p + 1;
445171169Smlaier	}
446171169Smlaier
447171169Smlaier	return (NULL);
448171169Smlaier}
449171169Smlaier
450171169Smlaiervoid evbuffer_setcb(struct evbuffer *buffer,
451171169Smlaier    void (*cb)(struct evbuffer *, size_t, size_t, void *),
452171169Smlaier    void *cbarg)
453171169Smlaier{
454171169Smlaier	buffer->cb = cb;
455171169Smlaier	buffer->cbarg = cbarg;
456171169Smlaier}
457