summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorplunky <plunky@NetBSD.org>2009-11-02 10:14:28 +0000
committerplunky <plunky@NetBSD.org>2009-11-02 10:14:28 +0000
commit212bd4a35caec55e4db0110e6cfd1aa87dcf857a (patch)
tree0a419630de30a848daa57bf94c4d27ae03659a68 /lib
parentc75313ecdf198c237300eb00a95ba57ccd230743 (diff)
remove old libevent sources
Diffstat (limited to 'lib')
-rw-r--r--lib/libevent/Makefile95
-rw-r--r--lib/libevent/buffer.c410
-rw-r--r--lib/libevent/config.h239
-rw-r--r--lib/libevent/evbuffer.c435
-rw-r--r--lib/libevent/evdns.3367
-rw-r--r--lib/libevent/evdns.c2917
-rw-r--r--lib/libevent/evdns.h513
-rw-r--r--lib/libevent/event-internal.h99
-rw-r--r--lib/libevent/event.3623
-rw-r--r--lib/libevent/event.c1001
-rw-r--r--lib/libevent/event.h1163
-rw-r--r--lib/libevent/event_tagging.c433
-rw-r--r--lib/libevent/evhttp.h365
-rw-r--r--lib/libevent/evrpc-internal.h88
-rw-r--r--lib/libevent/evrpc.c645
-rw-r--r--lib/libevent/evrpc.h487
-rw-r--r--lib/libevent/evsignal.h57
-rw-r--r--lib/libevent/evutil.c94
-rw-r--r--lib/libevent/evutil.h94
-rw-r--r--lib/libevent/http-internal.h155
-rw-r--r--lib/libevent/http.c2748
-rw-r--r--lib/libevent/kqueue.c422
-rw-r--r--lib/libevent/log.c177
-rw-r--r--lib/libevent/log.h52
-rw-r--r--lib/libevent/min_heap.h150
-rw-r--r--lib/libevent/poll.c376
-rw-r--r--lib/libevent/shlib_version5
-rw-r--r--lib/libevent/signal.c339
28 files changed, 0 insertions, 14549 deletions
diff --git a/lib/libevent/Makefile b/lib/libevent/Makefile
deleted file mode 100644
index b2457bae710..00000000000
--- a/lib/libevent/Makefile
+++ /dev/null
@@ -1,95 +0,0 @@
-# $NetBSD: Makefile,v 1.8 2009/08/19 15:18:05 tls Exp $
-# @(#)Makefile 8.1 (Berkeley) 6/4/93
-
-NOLINT= # Until someone explains to me how to avoid lint stupidity
-USE_SHLIBDIR= yes
-
-CPPFLAGS+=-I${.CURDIR} -fno-strict-aliasing
-.include <bsd.own.mk>
-
-LIB= event
-SRCS= buffer.c evbuffer.c evdns.c event.c event_tagging.c evrpc.c evutil.c \
- http.c kqueue.c log.c poll.c signal.c
-
-INCS= evdns.h event.h evhttp.h evrpc.h evutil.h event-config.h
-INCSDIR=/usr/include
-
-MAN= evdns.3 event.3
-
-MLINKS+=event.3 event_init.3
-MLINKS+=event.3 event_dispatch.3
-MLINKS+=event.3 event_loop.3
-MLINKS+=event.3 event_loopexit.3
-MLINKS+=event.3 event_loopbreak.3
-MLINKS+=event.3 event_base_dispatch.3
-MLINKS+=event.3 event_base_free.3
-MLINKS+=event.3 event_base_loop.3
-MLINKS+=event.3 event_base_loopexit.3
-MLINKS+=event.3 event_base_loopbreak.3
-MLINKS+=event.3 event_base_set.3
-MLINKS+=event.3 event_set.3
-MLINKS+=event.3 event_add.3
-MLINKS+=event.3 event_del.3
-MLINKS+=event.3 event_once.3
-MLINKS+=event.3 event_base_once.3
-MLINKS+=event.3 event_pending.3
-MLINKS+=event.3 event_initialized.3
-
-MLINKS+=event.3 evtimer_set.3
-MLINKS+=event.3 evtimer_add.3
-MLINKS+=event.3 evtimer_del.3
-MLINKS+=event.3 evtimer_pending.3
-MLINKS+=event.3 evtimer_initialized.3
-
-MLINKS+=event.3 signal_set.3
-MLINKS+=event.3 signal_add.3
-MLINKS+=event.3 signal_del.3
-MLINKS+=event.3 signal_pending.3
-MLINKS+=event.3 signal_initialized.3
-
-MLINKS+=event.3 bufferevent_new.3
-MLINKS+=event.3 bufferevent_free.3
-MLINKS+=event.3 bufferevent_write.3
-MLINKS+=event.3 bufferevent_write_buffer.3
-MLINKS+=event.3 bufferevent_read.3
-MLINKS+=event.3 bufferevent_enable.3
-MLINKS+=event.3 bufferevent_disable.3
-MLINKS+=event.3 bufferevent_settimeout.3
-MLINKS+=event.3 bufferevent_base_set.3
-
-MLINKS+=event.3 evbuffer_new.3
-MLINKS+=event.3 evbuffer_free.3
-MLINKS+=event.3 evbuffer_add.3
-MLINKS+=event.3 evbuffer_add_buffer.3
-MLINKS+=event.3 evbuffer_add_printf.3
-MLINKS+=event.3 evbuffer_add_vprintf.3
-MLINKS+=event.3 evbuffer_drain.3
-MLINKS+=event.3 evbuffer_write.3
-MLINKS+=event.3 evbuffer_read.3
-MLINKS+=event.3 evbuffer_find.3
-MLINKS+=event.3 evbuffer_readline.3
-
-MLINKS+=event.3 evhttp_new.3
-MLINKS+=event.3 evhttp_bind_socket.3
-MLINKS+=event.3 evhttp_free.3
-
-MLINKS+=evdns.3 evdns_init.3
-MLINKS+=evdns.3 evdns_shutdown.3
-MLINKS+=evdns.3 evdns_err_to_string.3
-MLINKS+=evdns.3 evdns_nameserver_add.3
-MLINKS+=evdns.3 evdns_count_nameservers.3
-MLINKS+=evdns.3 evdns_clear_nameservers_and_suspend.3
-MLINKS+=evdns.3 evdns_resume.3
-MLINKS+=evdns.3 evdns_nameserver_ip_add.3
-MLINKS+=evdns.3 evdns_resolve_ipv4.3
-MLINKS+=evdns.3 evdns_resolve_reverse.3
-MLINKS+=evdns.3 evdns_resolv_conf_parse.3
-MLINKS+=evdns.3 evdns_search_clear.3
-MLINKS+=evdns.3 evdns_search_add.3
-MLINKS+=evdns.3 evdns_search_ndots_set.3
-MLINKS+=evdns.3 evdns_set_log_fn.3
-
-event-config.h: config.h
- sed -e 's/#define /#define _EVENT_/' ${.ALLSRC} > ${.OBJDIR}/${.TARGET}
-
-.include <bsd.lib.mk>
diff --git a/lib/libevent/buffer.c b/lib/libevent/buffer.c
deleted file mode 100644
index 7e08a30abd4..00000000000
--- a/lib/libevent/buffer.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/* $NetBSD: buffer.c,v 1.5 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <unistd.h>
-
-#include "event.h"
-#include "config.h"
-#include "evutil.h"
-
-struct evbuffer *
-evbuffer_new(void)
-{
- struct evbuffer *buffer;
-
- buffer = calloc(1, sizeof(struct evbuffer));
-
- return (buffer);
-}
-
-void
-evbuffer_free(struct evbuffer *buffer)
-{
- if (buffer->orig_buffer != NULL)
- free(buffer->orig_buffer);
- free(buffer);
-}
-
-/*
- * This is a destructive add. The data from one buffer moves into
- * the other buffer.
- */
-
-#define SWAP(x,y) do { \
- (x)->buffer = (y)->buffer; \
- (x)->orig_buffer = (y)->orig_buffer; \
- (x)->misalign = (y)->misalign; \
- (x)->totallen = (y)->totallen; \
- (x)->off = (y)->off; \
-} while (0)
-
-int
-evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
-{
- int res;
-
- /* Short cut for better performance */
- if (outbuf->off == 0) {
- struct evbuffer tmp;
- size_t oldoff = inbuf->off;
-
- /* Swap them directly */
- SWAP(&tmp, outbuf);
- SWAP(outbuf, inbuf);
- SWAP(inbuf, &tmp);
-
- /*
- * Optimization comes with a price; we need to notify the
- * buffer if necessary of the changes. oldoff is the amount
- * of data that we transfered from inbuf to outbuf
- */
- if (inbuf->off != oldoff && inbuf->cb != NULL)
- (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
- if (oldoff && outbuf->cb != NULL)
- (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
-
- return (0);
- }
-
- res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
- if (res == 0) {
- /* We drain the input buffer on success */
- evbuffer_drain(inbuf, inbuf->off);
- }
-
- return (res);
-}
-
-int
-evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
-{
- char *buffer;
- size_t space;
- size_t oldoff = buf->off;
- int sz;
- va_list aq;
-
- /* make sure that at least some space is available */
- evbuffer_expand(buf, 64);
- for (;;) {
- size_t used = buf->misalign + buf->off;
- buffer = (char *)buf->buffer + buf->off;
- assert(buf->totallen >= used);
- space = buf->totallen - used;
-
- va_copy(aq, ap);
-
- sz = evutil_vsnprintf(buffer, space, fmt, aq);
-
- va_end(aq);
-
- if (sz < 0)
- return (-1);
- if ((size_t)sz < space) {
- buf->off += sz;
- if (buf->cb != NULL)
- (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
- return (sz);
- }
- if (evbuffer_expand(buf, sz + 1) == -1)
- return (-1);
-
- }
- /* NOTREACHED */
-}
-
-int
-evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
-{
- int res = -1;
- va_list ap;
-
- va_start(ap, fmt);
- res = evbuffer_add_vprintf(buf, fmt, ap);
- va_end(ap);
-
- return (res);
-}
-
-/* Reads data from an event buffer and drains the bytes read */
-
-int
-evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
-{
- size_t nread = datlen;
- if (nread >= buf->off)
- nread = buf->off;
-
- memcpy(data, buf->buffer, nread);
- evbuffer_drain(buf, nread);
-
- return (nread);
-}
-
-/*
- * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
- * The returned buffer needs to be freed by the called.
- */
-
-char *
-evbuffer_readline(struct evbuffer *buffer)
-{
- u_char *data = EVBUFFER_DATA(buffer);
- size_t len = EVBUFFER_LENGTH(buffer);
- char *line;
- unsigned int i;
-
- for (i = 0; i < len; i++) {
- if (data[i] == '\r' || data[i] == '\n')
- break;
- }
-
- if (i == len)
- return (NULL);
-
- if ((line = malloc(i + 1)) == NULL) {
- fprintf(stderr, "%s: out of memory\n", __func__);
- evbuffer_drain(buffer, i);
- return (NULL);
- }
-
- memcpy(line, data, i);
- line[i] = '\0';
-
- /*
- * Some protocols terminate a line with '\r\n', so check for
- * that, too.
- */
- if ( i < len - 1 ) {
- char fch = data[i], sch = data[i+1];
-
- /* Drain one more character if needed */
- if ( (sch == '\r' || sch == '\n') && sch != fch )
- i += 1;
- }
-
- evbuffer_drain(buffer, i + 1);
-
- return (line);
-}
-
-/* Adds data to an event buffer */
-
-static void
-evbuffer_align(struct evbuffer *buf)
-{
- memmove(buf->orig_buffer, buf->buffer, buf->off);
- buf->buffer = buf->orig_buffer;
- buf->misalign = 0;
-}
-
-/* Expands the available space in the event buffer to at least datlen */
-
-int
-evbuffer_expand(struct evbuffer *buf, size_t datlen)
-{
- size_t need = buf->misalign + buf->off + datlen;
-
- /* If we can fit all the data, then we don't have to do anything */
- if (buf->totallen >= need)
- return (0);
-
- /*
- * If the misalignment fulfills our data needs, we just force an
- * alignment to happen. Afterwards, we have enough space.
- */
- if (buf->misalign >= datlen) {
- evbuffer_align(buf);
- } else {
- void *newbuf;
- size_t length = buf->totallen;
-
- if (length < 256)
- length = 256;
- while (length < need)
- length <<= 1;
-
- if (buf->orig_buffer != buf->buffer)
- evbuffer_align(buf);
- if ((newbuf = realloc(buf->buffer, length)) == NULL)
- return (-1);
-
- buf->orig_buffer = buf->buffer = newbuf;
- buf->totallen = length;
- }
-
- return (0);
-}
-
-int
-evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
-{
- size_t need = buf->misalign + buf->off + datlen;
- size_t oldoff = buf->off;
-
- if (buf->totallen < need) {
- if (evbuffer_expand(buf, datlen) == -1)
- return (-1);
- }
-
- memcpy(buf->buffer + buf->off, data, datlen);
- buf->off += datlen;
-
- if (datlen && buf->cb != NULL)
- (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
-
- return (0);
-}
-
-void
-evbuffer_drain(struct evbuffer *buf, size_t len)
-{
- size_t oldoff = buf->off;
-
- if (len >= buf->off) {
- buf->off = 0;
- buf->buffer = buf->orig_buffer;
- buf->misalign = 0;
- goto done;
- }
-
- buf->buffer += len;
- buf->misalign += len;
-
- buf->off -= len;
-
- done:
- /* Tell someone about changes in this buffer */
- if (buf->off != oldoff && buf->cb != NULL)
- (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
-
-}
-
-/*
- * Reads data from a file descriptor into a buffer.
- */
-
-#define EVBUFFER_MAX_READ 4096
-
-int
-evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
-{
- u_char *p;
- size_t oldoff = buf->off;
- int n = EVBUFFER_MAX_READ;
-
- if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
- n = EVBUFFER_MAX_READ;
- } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
- /*
- * It's possible that a lot of data is available for
- * reading. We do not want to exhaust resources
- * before the reader has a chance to do something
- * about it. If the reader does not tell us how much
- * data we should read, we artifically limit it.
- */
- if ((size_t)n > buf->totallen << 2)
- n = buf->totallen << 2;
- if (n < EVBUFFER_MAX_READ)
- n = EVBUFFER_MAX_READ;
- }
- if (howmuch < 0 || howmuch > n)
- howmuch = n;
-
- /* If we don't have FIONREAD, we might waste some space here */
- if (evbuffer_expand(buf, howmuch) == -1)
- return (-1);
-
- /* We can append new data at this point */
- p = buf->buffer + buf->off;
-
- n = read(fd, p, howmuch);
- if (n == -1)
- return (-1);
- if (n == 0)
- return (0);
-
- buf->off += n;
-
- /* Tell someone about changes in this buffer */
- if (buf->off != oldoff && buf->cb != NULL)
- (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
-
- return (n);
-}
-
-int
-evbuffer_write(struct evbuffer *buffer, int fd)
-{
- int n;
-
- n = write(fd, buffer->buffer, buffer->off);
- if (n == -1)
- return (-1);
- if (n == 0)
- return (0);
- evbuffer_drain(buffer, n);
-
- return (n);
-}
-
-u_char *
-evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
-{
- u_char *search = buffer->buffer, *end = search + buffer->off;
- u_char *p;
-
- while (search < end &&
- (p = memchr(search, *what, end - search)) != NULL) {
- if (p + len > end)
- break;
- if (memcmp(p, what, len) == 0)
- return (p);
- search = p + 1;
- }
-
- return (NULL);
-}
-
-void evbuffer_setcb(struct evbuffer *buffer,
- void (*cb)(struct evbuffer *, size_t, size_t, void *),
- void *cbarg)
-{
- buffer->cb = cb;
- buffer->cbarg = cbarg;
-}
diff --git a/lib/libevent/config.h b/lib/libevent/config.h
deleted file mode 100644
index 7fd73e2d868..00000000000
--- a/lib/libevent/config.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/* config.h. Generated from config.h.in by configure. */
-/* config.h.in. Generated from configure.in by autoheader. */
-
-/* Define if clock_gettime is available in libc */
-#define DNS_USE_CPU_CLOCK_FOR_ID 1
-
-/* Define is no secure id variant is available */
-/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
-
-/* Define to 1 if you have the `clock_gettime' function. */
-#define HAVE_CLOCK_GETTIME 1
-
-/* Define if /dev/poll is available */
-/* #undef HAVE_DEVPOLL */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define if your system supports the epoll system calls */
-/* #undef HAVE_EPOLL */
-
-/* Define to 1 if you have the `epoll_ctl' function. */
-/* #undef HAVE_EPOLL_CTL */
-
-/* Define if your system supports event ports */
-/* #undef HAVE_EVENT_PORTS */
-
-/* Define to 1 if you have the `fcntl' function. */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `getaddrinfo' function. */
-#define HAVE_GETADDRINFO 1
-
-/* Define to 1 if you have the `getnameinfo' function. */
-#define HAVE_GETNAMEINFO 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#define HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the `inet_ntop' function. */
-#define HAVE_INET_NTOP 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `kqueue' function. */
-#define HAVE_KQUEUE 1
-
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-/* #undef HAVE_LIBNSL */
-
-/* Define to 1 if you have the `resolv' library (-lresolv). */
-#define HAVE_LIBRESOLV 1
-
-/* Define to 1 if you have the `rt' library (-lrt). */
-#define HAVE_LIBRT 1
-
-/* Define to 1 if you have the `socket' library (-lsocket). */
-/* #undef HAVE_LIBSOCKET */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <netinet/in6.h> header file. */
-/* #undef HAVE_NETINET_IN6_H */
-
-/* Define to 1 if you have the `poll' function. */
-#define HAVE_POLL 1
-
-/* Define to 1 if you have the <poll.h> header file. */
-#define HAVE_POLL_H 1
-
-/* Define to 1 if you have the `port_create' function. */
-/* #undef HAVE_PORT_CREATE */
-
-/* Define to 1 if you have the <port.h> header file. */
-/* #undef HAVE_PORT_H */
-
-/* Define to 1 if you have the `select' function. */
-/* #undef HAVE_SELECT */
-
-/* Define if F_SETFD is defined in <fcntl.h> */
-#define HAVE_SETFD 1
-
-/* Define to 1 if you have the `sigaction' function. */
-#define HAVE_SIGACTION 1
-
-/* Define to 1 if you have the `signal' function. */
-#define HAVE_SIGNAL 1
-
-/* Define to 1 if you have the <signal.h> header file. */
-#define HAVE_SIGNAL_H 1
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define HAVE_STDARG_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-#define HAVE_STRLCPY 1
-
-/* Define to 1 if you have the `strsep' function. */
-#define HAVE_STRSEP 1
-
-/* Define to 1 if you have the `strtok_r' function. */
-#define HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the `strtoll' function. */
-#define HAVE_STRTOLL 1
-
-/* Define to 1 if the system has the type `struct in6_addr'. */
-#define HAVE_STRUCT_IN6_ADDR 1
-
-/* Define to 1 if you have the <sys/devpoll.h> header file. */
-/* #undef HAVE_SYS_DEVPOLL_H */
-
-/* Define to 1 if you have the <sys/epoll.h> header file. */
-/* #undef HAVE_SYS_EPOLL_H */
-
-/* Define to 1 if you have the <sys/event.h> header file. */
-#define HAVE_SYS_EVENT_H 1
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-#define HAVE_SYS_IOCTL_H 1
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the <sys/queue.h> header file. */
-#define HAVE_SYS_QUEUE_H 1
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-#define HAVE_SYS_SELECT_H 1
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#define HAVE_SYS_SOCKET_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-#define HAVE_TAILQFOREACH 1
-
-/* Define if timeradd is defined in <sys/time.h> */
-#define HAVE_TIMERADD 1
-
-/* Define if timerclear is defined in <sys/time.h> */
-#define HAVE_TIMERCLEAR 1
-
-/* Define if timercmp is defined in <sys/time.h> */
-#define HAVE_TIMERCMP 1
-
-/* Define if timerisset is defined in <sys/time.h> */
-#define HAVE_TIMERISSET 1
-
-/* Define to 1 if the system has the type `uint16_t'. */
-#define HAVE_UINT16_T 1
-
-/* Define to 1 if the system has the type `uint32_t'. */
-#define HAVE_UINT32_T 1
-
-/* Define to 1 if the system has the type `uint64_t'. */
-#define HAVE_UINT64_T 1
-
-/* Define to 1 if the system has the type `uint8_t'. */
-#define HAVE_UINT8_T 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* Define if kqueue works correctly with pipes */
-#define HAVE_WORKING_KQUEUE 1
-
-/* Name of package */
-#define PACKAGE "libevent"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME ""
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING ""
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION ""
-
-/* The size of `int', as computed by sizeof. */
-#define SIZEOF_INT 4
-
-/* The size of `long', as computed by sizeof. */
-#define SIZEOF_LONG 4
-
-/* The size of `long long', as computed by sizeof. */
-#define SIZEOF_LONG_LONG 8
-
-/* The size of `short', as computed by sizeof. */
-#define SIZEOF_SHORT 2
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define VERSION "1.4.11-stable"
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef pid_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef size_t */
-
-/* Define to unsigned int if you dont have it */
-/* #undef socklen_t */
diff --git a/lib/libevent/evbuffer.c b/lib/libevent/evbuffer.c
deleted file mode 100644
index 93e466915f8..00000000000
--- a/lib/libevent/evbuffer.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/* $NetBSD: evbuffer.c,v 1.5 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include "evutil.h"
-#include "event.h"
-
-/* prototypes */
-
-void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
-
-static int
-bufferevent_add(struct event *ev, int timeout)
-{
- struct timeval tv, *ptv = NULL;
-
- if (timeout) {
- evutil_timerclear(&tv);
- tv.tv_sec = timeout;
- ptv = &tv;
- }
-
- return (event_add(ev, ptv));
-}
-
-/*
- * This callback is executed when the size of the input buffer changes.
- * We use it to apply back pressure on the reading side.
- */
-
-void
-bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now,
- void *arg) {
- struct bufferevent *bufev = arg;
- /*
- * If we are below the watermark then reschedule reading if it's
- * still enabled.
- */
- if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
- evbuffer_setcb(buf, NULL, NULL);
-
- if (bufev->enabled & EV_READ)
- bufferevent_add(&bufev->ev_read, bufev->timeout_read);
- }
-}
-
-static void
-bufferevent_readcb(int fd, short event, void *arg)
-{
- struct bufferevent *bufev = arg;
- int res = 0;
- short what = EVBUFFER_READ;
- size_t len;
- int howmuch = -1;
-
- if (event == EV_TIMEOUT) {
- what |= EVBUFFER_TIMEOUT;
- goto error;
- }
-
- /*
- * If we have a high watermark configured then we don't want to
- * read more data than would make us reach the watermark.
- */
- if (bufev->wm_read.high != 0) {
- howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
- /* we might have lowered the watermark, stop reading */
- if (howmuch <= 0) {
- struct evbuffer *buf = bufev->input;
- event_del(&bufev->ev_read);
- evbuffer_setcb(buf,
- bufferevent_read_pressure_cb, bufev);
- return;
- }
- }
-
- res = evbuffer_read(bufev->input, fd, howmuch);
- if (res == -1) {
- if (errno == EAGAIN || errno == EINTR)
- goto reschedule;
- /* error case */
- what |= EVBUFFER_ERROR;
- } else if (res == 0) {
- /* eof case */
- what |= EVBUFFER_EOF;
- }
-
- if (res <= 0)
- goto error;
-
- bufferevent_add(&bufev->ev_read, bufev->timeout_read);
-
- /* See if this callbacks meets the water marks */
- len = EVBUFFER_LENGTH(bufev->input);
- if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
- return;
- if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
- struct evbuffer *buf = bufev->input;
- event_del(&bufev->ev_read);
-
- /* Now schedule a callback for us when the buffer changes */
- evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
- }
-
- /* Invoke the user callback - must always be called last */
- if (bufev->readcb != NULL)
- (*bufev->readcb)(bufev, bufev->cbarg);
- return;
-
- reschedule:
- bufferevent_add(&bufev->ev_read, bufev->timeout_read);
- return;
-
- error:
- (*bufev->errorcb)(bufev, what, bufev->cbarg);
-}
-
-static void
-bufferevent_writecb(int fd, short event, void *arg)
-{
- struct bufferevent *bufev = arg;
- int res = 0;
- short what = EVBUFFER_WRITE;
-
- if (event == EV_TIMEOUT) {
- what |= EVBUFFER_TIMEOUT;
- goto error;
- }
-
- if (EVBUFFER_LENGTH(bufev->output)) {
- res = evbuffer_write(bufev->output, fd);
- if (res == -1) {
- if (errno == EAGAIN ||
- errno == EINTR ||
- errno == EINPROGRESS)
- goto reschedule;
- /* error case */
- what |= EVBUFFER_ERROR;
- } else if (res == 0) {
- /* eof case */
- what |= EVBUFFER_EOF;
- }
- if (res <= 0)
- goto error;
- }
-
- if (EVBUFFER_LENGTH(bufev->output) != 0)
- bufferevent_add(&bufev->ev_write, bufev->timeout_write);
-
- /*
- * Invoke the user callback if our buffer is drained or below the
- * low watermark.
- */
- if (bufev->writecb != NULL &&
- EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
- (*bufev->writecb)(bufev, bufev->cbarg);
-
- return;
-
- reschedule:
- if (EVBUFFER_LENGTH(bufev->output) != 0)
- bufferevent_add(&bufev->ev_write, bufev->timeout_write);
- return;
-
- error:
- (*bufev->errorcb)(bufev, what, bufev->cbarg);
-}
-
-/*
- * Create a new buffered event object.
- *
- * The read callback is invoked whenever we read new data.
- * The write callback is invoked whenever the output buffer is drained.
- * The error callback is invoked on a write/read error or on EOF.
- *
- * Both read and write callbacks maybe NULL. The error callback is not
- * allowed to be NULL and have to be provided always.
- */
-
-struct bufferevent *
-bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
- everrorcb errorcb, void *cbarg)
-{
- struct bufferevent *bufev;
-
- if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
- return (NULL);
-
- if ((bufev->input = evbuffer_new()) == NULL) {
- free(bufev);
- return (NULL);
- }
-
- if ((bufev->output = evbuffer_new()) == NULL) {
- evbuffer_free(bufev->input);
- free(bufev);
- return (NULL);
- }
-
- event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
- event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
-
- bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);
-
- /*
- * Set to EV_WRITE so that using bufferevent_write is going to
- * trigger a callback. Reading needs to be explicitly enabled
- * because otherwise no data will be available.
- */
- bufev->enabled = EV_WRITE;
-
- return (bufev);
-}
-
-void
-bufferevent_setcb(struct bufferevent *bufev,
- evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg)
-{
- bufev->readcb = readcb;
- bufev->writecb = writecb;
- bufev->errorcb = errorcb;
-
- bufev->cbarg = cbarg;
-}
-
-void
-bufferevent_setfd(struct bufferevent *bufev, int fd)
-{
- event_del(&bufev->ev_read);
- event_del(&bufev->ev_write);
-
- event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
- event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
- if (bufev->ev_base != NULL) {
- event_base_set(bufev->ev_base, &bufev->ev_read);
- event_base_set(bufev->ev_base, &bufev->ev_write);
- }
-
- /* might have to manually trigger event registration */
-}
-
-int
-bufferevent_priority_set(struct bufferevent *bufev, int priority)
-{
- if (event_priority_set(&bufev->ev_read, priority) == -1)
- return (-1);
- if (event_priority_set(&bufev->ev_write, priority) == -1)
- return (-1);
-
- return (0);
-}
-
-/* Closing the file descriptor is the responsibility of the caller */
-
-void
-bufferevent_free(struct bufferevent *bufev)
-{
- event_del(&bufev->ev_read);
- event_del(&bufev->ev_write);
-
- evbuffer_free(bufev->input);
- evbuffer_free(bufev->output);
-
- free(bufev);
-}
-
-/*
- * Returns 0 on success;
- * -1 on failure.
- */
-
-int
-bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
-{
- int res;
-
- res = evbuffer_add(bufev->output, data, size);
-
- if (res == -1)
- return (res);
-
- /* If everything is okay, we need to schedule a write */
- if (size > 0 && (bufev->enabled & EV_WRITE))
- bufferevent_add(&bufev->ev_write, bufev->timeout_write);
-
- return (res);
-}
-
-int
-bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
-{
- int res;
-
- res = bufferevent_write(bufev, buf->buffer, buf->off);
- if (res != -1)
- evbuffer_drain(buf, buf->off);
-
- return (res);
-}
-
-size_t
-bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
-{
- struct evbuffer *buf = bufev->input;
-
- if (buf->off < size)
- size = buf->off;
-
- /* Copy the available data to the user buffer */
- memcpy(data, buf->buffer, size);
-
- if (size)
- evbuffer_drain(buf, size);
-
- return (size);
-}
-
-int
-bufferevent_enable(struct bufferevent *bufev, short event)
-{
- if (event & EV_READ) {
- if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
- return (-1);
- }
- if (event & EV_WRITE) {
- if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
- return (-1);
- }
-
- bufev->enabled |= event;
- return (0);
-}
-
-int
-bufferevent_disable(struct bufferevent *bufev, short event)
-{
- if (event & EV_READ) {
- if (event_del(&bufev->ev_read) == -1)
- return (-1);
- }
- if (event & EV_WRITE) {
- if (event_del(&bufev->ev_write) == -1)
- return (-1);
- }
-
- bufev->enabled &= ~event;
- return (0);
-}
-
-/*
- * Sets the read and write timeout for a buffered event.
- */
-
-void
-bufferevent_settimeout(struct bufferevent *bufev,
- int timeout_read, int timeout_write) {
- bufev->timeout_read = timeout_read;
- bufev->timeout_write = timeout_write;
-
- if (event_pending(&bufev->ev_read, EV_READ, NULL))
- bufferevent_add(&bufev->ev_read, timeout_read);
- if (event_pending(&bufev->ev_write, EV_WRITE, NULL))
- bufferevent_add(&bufev->ev_write, timeout_write);
-}
-
-/*
- * Sets the water marks
- */
-
-void
-bufferevent_setwatermark(struct bufferevent *bufev, short events,
- size_t lowmark, size_t highmark)
-{
- if (events & EV_READ) {
- bufev->wm_read.low = lowmark;
- bufev->wm_read.high = highmark;
- }
-
- if (events & EV_WRITE) {
- bufev->wm_write.low = lowmark;
- bufev->wm_write.high = highmark;
- }
-
- /* If the watermarks changed then see if we should call read again */
- bufferevent_read_pressure_cb(bufev->input,
- 0, EVBUFFER_LENGTH(bufev->input), bufev);
-}
-
-int
-bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
-{
- int res;
-
- bufev->ev_base = base;
-
- res = event_base_set(base, &bufev->ev_read);
- if (res == -1)
- return (res);
-
- res = event_base_set(base, &bufev->ev_write);
- return (res);
-}
diff --git a/lib/libevent/evdns.3 b/lib/libevent/evdns.3
deleted file mode 100644
index 3cb482298d9..00000000000
--- a/lib/libevent/evdns.3
+++ /dev/null
@@ -1,367 +0,0 @@
-.\" $NetBSD: evdns.3,v 1.6 2009/06/22 08:31:13 tron Exp $
-.\"
-.\" Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.Dd May 14, 2008
-.Dt EVDNS 3
-.Os
-.Sh NAME
-.Nm evdns_init
-.Nm evdns_shutdown
-.Nm evdns_err_to_string
-.Nm evdns_nameserver_add
-.Nm evdns_count_nameservers
-.Nm evdns_clear_nameservers_and_suspend
-.Nm evdns_resume
-.Nm evdns_nameserver_ip_add
-.Nm evdns_resolve_ipv4
-.Nm evdns_resolve_reverse
-.Nm evdns_resolv_conf_parse
-.Nm evdns_search_clear
-.Nm evdns_search_add
-.Nm evdns_search_ndots_set
-.Nm evdns_set_log_fn
-.Nd asynchronous functions for DNS resolution
-.Sh SYNOPSIS
-.In sys/time.h
-.In event.h
-.In evdns.h
-.Ft int
-.Fn evdns_init
-.Ft void
-.Fn evdns_shutdown "int fail_requests"
-.Ft "const char *"
-.Fn evdns_err_to_string "int err"
-.Ft int
-.Fn evdns_nameserver_add "unsigned long int address"
-.Ft int
-.Fn evdns_count_nameservers
-.Ft int
-.Fn evdns_clear_nameservers_and_suspend
-.Ft int
-.Fn evdns_resume
-.Ft int
-.Fn evdns_nameserver_ip_add "const char *ip_as_string"
-.Ft int
-.Fn evdns_resolve_ipv4 "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
-.Ft int
-.Fn evdns_resolve_reverse "struct in_addr *in" "int flags" "evdns_callback_type callback" "void *ptr"
-.Ft int
-.Fn evdns_resolv_conf_parse "int flags" "const char *"
-.Ft void
-.Fn evdns_search_clear
-.Ft void
-.Fn evdns_search_add "const char *domain"
-.Ft void
-.Fn evdns_search_ndots_set "const int ndots"
-.Ft void
-.Fn evdns_set_log_fn "evdns_debug_log_fn_type fn"
-.Sh DESCRIPTION
-Welcome, gentle reader
-.Pp
-Async DNS lookups are really a whole lot harder than they should be,
-mostly stemming from the fact that the libc resolver has never been
-very good at them.
-Before you use this library you should see if libc
-can do the job for you with the modern async call getaddrinfo_a
-(see http://www.imperialviolet.org/page25.html#e498).
-Otherwise, please continue.
-.Pp
-This code is based on libevent and you must call
-.Fn event_init
-before
-any of the APIs in this file.
-You must also seed the OpenSSL random
-source if you are using OpenSSL for ids (see below).
-.Pp
-This library is designed to be included and shipped with your source
-code.
-You statically link with it.
-You should also test for the existence of
-.Xr strtok_r 3
-and define
-.Dv HAVE_STRTOK_R
-if you have it.
-.Pp
-The DNS protocol requires a good source of id numbers and these
-numbers should be unpredictable for spoofing reasons.
-There are three methods for generating them here and you must define
-exactly one of them.
-In increasing order of preference:
-.Pp
-.Bl -tag -width "DNS_USE_GETTIMEOFDAY_FOR_ID" -compact -offset indent
-.It Dv DNS_USE_GETTIMEOFDAY_FOR_ID
-Using the bottom 16 bits of the usec result from gettimeofday.
-This is a pretty poor solution but should work anywhere.
-.It Dv DNS_USE_CPU_CLOCK_FOR_ID
-Using the bottom 16 bits of the nsec result from the CPU's time
-counter.
-This is better, but may not work everywhere.
-Requires POSIX realtime support and you'll need to link against
-.Lb librt
-on glibc systems at least.
-.It Dv DNS_USE_OPENSSL_FOR_ID
-Uses the OpenSSL RAND_bytes call to generate the data.
-You must have seeded the pool before making any calls to this
-library.
-.El
-.Pp
-The library keeps track of the state of nameservers and will avoid
-them when they go down.
-Otherwise it will round robin between them.
-.Pp
-Quick start guide:
-.Bd -literal
-#include \*[Lt]evdns.h\*[Gt]
-void callback(int result, char type, int count, int ttl,
- void *addresses, void *arg);
-
-evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
-evdns_resolve("www.hostname.com", 0, callback, NULL);
-.Ed
-.Pp
-When the lookup is complete the callback function is called.
-The first argument will be one of the DNS_ERR_* defines in evdns.h.
-Hopefully it will be
-.Dv DNS_ERR_NONE ,
-in which case type will be
-.Dv DNS_IPv4_A ,
-count will be the number of IP addresses, ttl is the time
-which the data can be cached for (in seconds), addresses will point
-to an array of uint32_t's and arg will be whatever you passed to
-.Fn evdns_resolve .
-.Pp
-Searching:
-.Pp
-In order for this library to be a good replacement for glibc's resolver it
-supports searching.
-This involves setting a list of default domains, in which names
-will be queried for.
-The number of dots in the query name determines the order in which
-this list is used.
-.Pp
-Searching appears to be a single lookup from the point of view of the API,
-although many DNS queries may be generated from a single call to
-.Fn evdns_resolve .
-Searching can also drastically slow down the resolution of names.
-.Pp
-To disable searching:
-.Bl -enum -compact -offset indent
-.It
-Never set it up.
-If you never call
-.Fn evdns_resolv_conf_parse ,
-.Fn evdns_init ,
-or
-.Fn evdns_search_add
-then no searching will occur.
-.It
-If you do call
-.Fn evdns_resolv_conf_parse
-then don't pass
-.Dv DNS_OPTION_SEARCH
-(or
-.Dv DNS_OPTIONS_ALL ,
-which implies it).
-.It
-When calling
-.Fn evdns_resolve ,
-pass the
-.Dv DNS_QUERY_NO_SEARCH
-flag.
-.El
-.Pp
-The order of searches depends on the number of dots in the name.
-If the number is greater than the
-.Sy ndots
-setting then the names is first tried globally.
-Otherwise each search domain is appended in turn.
-.Pp
-The
-.Sy ndots
-setting can either be set from a
-.Pa resolv.conf ,
-or by calling
-.Fn evdns_search_ndots_set .
-.Pp
-For example, with
-.Sy ndots
-set to 1 (the default) and a search domain list of
-["myhome.net"]:
- Query: www
- Order: www.myhome.net, www.
-.Pp
- Query: www.abc
- Order: www.abc., www.abc.myhome.net
-.Ss API reference
-.Bl -tag -width 0123456
-.It Ft int Fn evdns_init
-Initializes support for non-blocking name resolution by calling
-.Fn evdns_resolv_conf_parse .
-.It Ft int Fn evdns_nameserver_add "unsigned long int address"
-Add a nameserver.
-The
-.Ar address
-should be an IP address in network byte order.
-The type of address is chosen so that it matches in_addr.s_addr.
-Returns non-zero on error.
-.It Ft int Fn evdns_nameserver_ip_add "const char *ip_as_string"
-This wraps the above function by parsing a string as an IP
-address and adds it as a nameserver.
-Returns non-zero on error
-.It Ft int Fn evdns_resolve "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
-Resolve a name.
-The
-.Ar name
-parameter should be a DNS name.
-The
-.Ar flags
-parameter should be 0, or
-.Dv DNS_QUERY_NO_SEARCH
-which disables searching for this query (see definition of
-searching above).
-.Pp
-The
-.Ar callback
-argument is a function which is called when
-this query completes and
-.Ar ptr
-is an argument which is passed
-to that callback function.
-.Pp
-Returns non-zero on error
-.It Ft void Fn evdns_search_clear
-Clears the list of search domains
-.It Ft void Fn evdns_search_add "const char *domain"
-Add a domain to the list of search domains
-.It Ft void Fn evdns_search_ndots_set "int ndots"
-Set the number of dots which, when found in a name, causes
-the first query to be without any search domain.
-.It Ft int Fn evdns_count_nameservers "void"
-Return the number of configured nameservers (not necessarily the
-number of running nameservers).
-This is useful for double-checking whether our calls to the various
-nameserver configuration functions have been successful.
-.It Ft int Fn evdns_clear_nameservers_and_suspend "void"
-Remove all currently configured nameservers, and suspend all pending
-resolves.
-Resolves will not necessarily be re-attempted until
-.Fn evdns_resume
-is called.
-.It Ft int Fn evdns_resume "void"
-Re-attempt resolves left in limbo after an earlier call to
-.Fn evdns_clear_nameservers_and_suspend .
-.It Ft int Fn evdns_resolv_conf_parse "int flags" "const char *filename"
-Parse a resolv.conf like file from the given filename.
-.Pp
-See the man page for
-.Xr resolv.conf 5
-for the format of this file.
-The flags argument determines what information is parsed from
-this file:
-.Bl -tag -width "DNS_OPTION_NAMESERVERS" -offset indent -compact -nested
-.It Dv DNS_OPTION_SEARCH
-domain, search and ndots options
-.It DNS_OPTION_NAMESERVERS
-nameserver lines
-.It Dv DNS_OPTION_MISC
-timeout and attempts options
-.It Dv DNS_OPTIONS_ALL
-all of the above
-.El
-.Pp
-The following directives are not parsed from the file:
-.Sy sortlist ,
-.Sy rotate ,
-.Sy no-check-names ,
-.Sy inet6 ,
-.Sy debug .
-.Pp
-Returns non-zero on error:
-.Bl -tag -width "0" -offset indent -compact -nested
-.It 0
-no errors
-.It 1
-failed to open file
-.It 2
-failed to stat file
-.It 3
-file too large
-.It 4
-out of memory
-.It 5
-short read from file
-.El
-.El
-.Ss Internals
-Requests are kept in two queues.
-The first is the inflight queue.
-In this queue requests have an allocated transaction id and
-nameserver.
-They will soon be transmitted if they haven't already been.
-.Pp
-The second is the waiting queue.
-The size of the inflight ring is limited and all other requests
-wait in waiting queue for space.
-This bounds the number of concurrent requests so that we don't
-flood the nameserver.
-Several algorithms require a full walk of the inflight
-queue and so bounding its size keeps thing going nicely under huge
-(many thousands of requests) loads.
-.Pp
-If a nameserver loses too many requests it is considered down and we
-try not to use it.
-After a while we send a probe to that nameserver (a lookup for
-google.com) and, if it replies, we consider it working again.
-If the nameserver fails a probe we wait longer to try again
-with the next probe.
-.Sh SEE ALSO
-.Xr event 3 ,
-.Xr gethostbyname 3 ,
-.Xr resolv.conf 5
-.Sh HISTORY
-The
-.Nm evdns
-API was developed by Adam Langley on top of the
-.Nm libevent
-API.
-The code was integrated into
-.Nm Tor
-by Nick Mathewson and finally put into
-.Nm libevent
-itself by Niels Provos.
-.Sh AUTHORS
-The
-.Nm evdns
-API and code was written by Adam Langley with significant
-contributions by Nick Mathewson.
-.Sh BUGS
-This documentation is neither complete nor authoritative.
-If you are in doubt about the usage of this API then
-check the source code to find out how it works, write
-up the missing piece of documentation and send it to
-me for inclusion in this man page.
diff --git a/lib/libevent/evdns.c b/lib/libevent/evdns.c
deleted file mode 100644
index 40692966fd6..00000000000
--- a/lib/libevent/evdns.c
+++ /dev/null
@@ -1,2917 +0,0 @@
-/* $NetBSD: evdns.c,v 1.3 2009/07/08 21:23:53 tls Exp $ */
-
-/* The original version of this module was written by Adam Langley; for
- * a history of modifications, check out the subversion logs.
- *
- * When editing this module, try to keep it re-mergeable by Adam. Don't
- * reformat the whitespace, add Tor dependencies, or so on.
- *
- * TODO:
- * - Support IPv6 and PTR records.
- * - Replace all externally visible magic numbers with #defined constants.
- * - Write doccumentation for APIs of all external functions.
- */
-
-/* Async DNS Library
- * Adam Langley <agl@imperialviolet.org>
- * http://www.imperialviolet.org/eventdns.html
- * Public Domain code
- *
- * This software is Public Domain. To view a copy of the public domain dedication,
- * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
- * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
- *
- * I ask and expect, but do not require, that all derivative works contain an
- * attribution similar to:
- * Parts developed by Adam Langley <agl@imperialviolet.org>
- *
- * You may wish to replace the word "Parts" with something else depending on
- * the amount of original code.
- *
- * (Derivative works does not include programs which link against, run or include
- * the source verbatim in their source distributions)
- *
- * Version: 0.1b
- */
-
-#include <sys/types.h>
-#include "config.h"
-
-#ifdef DNS_USE_FTIME_FOR_ID
-#include <sys/timeb.h>
-#endif
-
-#ifndef DNS_USE_CPU_CLOCK_FOR_ID
-#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
-#ifndef DNS_USE_OPENSSL_FOR_ID
-#ifndef DNS_USE_FTIME_FOR_ID
-#error Must configure at least one id generation method.
-#error Please see the documentation.
-#endif
-#endif
-#endif
-#endif
-
-/* #define _POSIX_C_SOURCE 200507 */
-#define _GNU_SOURCE
-
-#ifdef DNS_USE_CPU_CLOCK_FOR_ID
-#ifdef DNS_USE_OPENSSL_FOR_ID
-#error Multiple id options selected
-#endif
-#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
-#error Multiple id options selected
-#endif
-#include <time.h>
-#endif
-
-#ifdef DNS_USE_OPENSSL_FOR_ID
-#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
-#error Multiple id options selected
-#endif
-#include <openssl/rand.h>
-#endif
-
-#ifndef _FORTIFY_SOURCE
-#define _FORTIFY_SOURCE 3
-#endif
-
-#include <string.h>
-#include <fcntl.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <limits.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "evdns.h"
-#include "evutil.h"
-#include "log.h"
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-
-#define EVDNS_LOG_DEBUG 0
-#define EVDNS_LOG_WARN 1
-
-#ifndef HOST_NAME_MAX
-#define HOST_NAME_MAX 255
-#endif
-
-#include <stdio.h>
-
-#undef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-
-#ifdef __USE_ISOC99B
-/* libevent doesn't work without this */
-typedef ev_uint8_t u_char;
-typedef unsigned int uint;
-#endif
-#include <event.h>
-
-#define u64 ev_uint64_t
-#define u32 ev_uint32_t
-#define u16 ev_uint16_t
-#define u8 ev_uint8_t
-
-#define MAX_ADDRS 32 /* maximum number of addresses from a single packet */
-/* which we bother recording */
-
-#define TYPE_A EVDNS_TYPE_A
-#define TYPE_CNAME 5
-#define TYPE_PTR EVDNS_TYPE_PTR
-#define TYPE_AAAA EVDNS_TYPE_AAAA
-
-#define CLASS_INET EVDNS_CLASS_INET
-
-struct request {
- u8 *request; /* the dns packet data */
- unsigned int request_len;
- int reissue_count;
- int tx_count; /* the number of times that this packet has been sent */
- unsigned int request_type; /* TYPE_PTR or TYPE_A */
- void *user_pointer; /* the pointer given to us for this request */
- evdns_callback_type user_callback;
- struct nameserver *ns; /* the server which we last sent it */
-
- /* elements used by the searching code */
- int search_index;
- struct search_state *search_state;
- char *search_origname; /* needs to be free()ed */
- int search_flags;
-
- /* these objects are kept in a circular list */
- struct request *next, *prev;
-
- struct event timeout_event;
-
- u16 trans_id; /* the transaction id */
- char request_appended; /* true if the request pointer is data which follows this struct */
- char transmit_me; /* needs to be transmitted */
-};
-
-#ifndef HAVE_STRUCT_IN6_ADDR
-struct in6_addr {
- u8 s6_addr[16];
-};
-#endif
-
-struct reply {
- unsigned int type;
- unsigned int have_answer;
- union {
- struct {
- u32 addrcount;
- u32 addresses[MAX_ADDRS];
- } a;
- struct {
- u32 addrcount;
- struct in6_addr addresses[MAX_ADDRS];
- } aaaa;
- struct {
- char name[HOST_NAME_MAX];
- } ptr;
- } data;
-};
-
-struct nameserver {
- int socket; /* a connected UDP socket */
- u32 address;
- int failed_times; /* number of times which we have given this server a chance */
- int timedout; /* number of times in a row a request has timed out */
- struct event event;
- /* these objects are kept in a circular list */
- struct nameserver *next, *prev;
- struct event timeout_event; /* used to keep the timeout for */
- /* when we next probe this server. */
- /* Valid if state == 0 */
- char state; /* zero if we think that this server is down */
- char choked; /* true if we have an EAGAIN from this server's socket */
- char write_waiting; /* true if we are waiting for EV_WRITE events */
-};
-
-static struct request *req_head = NULL, *req_waiting_head = NULL;
-static struct nameserver *server_head = NULL;
-
-/* Represents a local port where we're listening for DNS requests. Right now, */
-/* only UDP is supported. */
-struct evdns_server_port {
- int socket; /* socket we use to read queries and write replies. */
- int refcnt; /* reference count. */
- char choked; /* Are we currently blocked from writing? */
- char closing; /* Are we trying to close this port, pending writes? */
- evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
- void *user_data; /* Opaque pointer passed to user_callback */
- struct event event; /* Read/write event */
- /* circular list of replies that we want to write. */
- struct server_request *pending_replies;
-};
-
-/* Represents part of a reply being built. (That is, a single RR.) */
-struct server_reply_item {
- struct server_reply_item *next; /* next item in sequence. */
- char *name; /* name part of the RR */
- u16 type : 16; /* The RR type */
- u16 class : 16; /* The RR class (usually CLASS_INET) */
- u32 ttl; /* The RR TTL */
- char is_name; /* True iff data is a label */
- u16 datalen; /* Length of data; -1 if data is a label */
- void *data; /* The contents of the RR */
-};
-
-/* Represents a request that we've received as a DNS server, and holds */
-/* the components of the reply as we're constructing it. */
-struct server_request {
- /* Pointers to the next and previous entries on the list of replies */
- /* that we're waiting to write. Only set if we have tried to respond */
- /* and gotten EAGAIN. */
- struct server_request *next_pending;
- struct server_request *prev_pending;
-
- u16 trans_id; /* Transaction id. */
- struct evdns_server_port *port; /* Which port received this request on? */
- struct sockaddr_storage addr; /* Where to send the response */
- socklen_t addrlen; /* length of addr */
-
- int n_answer; /* how many answer RRs have been set? */
- int n_authority; /* how many authority RRs have been set? */
- int n_additional; /* how many additional RRs have been set? */
-
- struct server_reply_item *answer; /* linked list of answer RRs */
- struct server_reply_item *authority; /* linked list of authority RRs */
- struct server_reply_item *additional; /* linked list of additional RRs */
-
- /* Constructed response. Only set once we're ready to send a reply. */
- /* Once this is set, the RR fields are cleared, and no more should be set. */
- char *response;
- size_t response_len;
-
- /* Caller-visible fields: flags, questions. */
- struct evdns_server_request base;
-};
-
-/* helper macro */
-#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
-
-/* Given a pointer to an evdns_server_request, get the corresponding */
-/* server_request. */
-#define TO_SERVER_REQUEST(base_ptr) \
- ((struct server_request*) \
- (((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
-
-/* The number of good nameservers that we have */
-static int global_good_nameservers = 0;
-
-/* inflight requests are contained in the req_head list */
-/* and are actually going out across the network */
-static int global_requests_inflight = 0;
-/* requests which aren't inflight are in the waiting list */
-/* and are counted here */
-static int global_requests_waiting = 0;
-
-static int global_max_requests_inflight = 64;
-
-static struct timeval global_timeout = {5, 0}; /* 5 seconds */
-static int global_max_reissues = 1; /* a reissue occurs when we get some errors from the server */
-static int global_max_retransmits = 3; /* number of times we'll retransmit a request which timed out */
-/* number of timeouts in a row before we consider this server to be down */
-static int global_max_nameserver_timeout = 3;
-
-/* These are the timeout values for nameservers. If we find a nameserver is down */
-/* we try to probe it at intervals as given below. Values are in seconds. */
-static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
-static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval);
-
-static struct nameserver *nameserver_pick(void);
-static void evdns_request_insert(struct request *req, struct request **head);
-static void nameserver_ready_callback(int fd, short events, void *arg);
-static int evdns_transmit(void);
-static int evdns_request_transmit(struct request *req);
-static void nameserver_send_probe(struct nameserver *const ns);
-static void search_request_finished(struct request *const);
-static int search_try_next(struct request *const req);
-static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
-static void evdns_requests_pump_waiting_queue(void);
-static u16 transaction_id_pick(void);
-static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
-static void request_submit(struct request *const req);
-
-static int server_request_free(struct server_request *req);
-static void server_request_free_answers(struct server_request *req);
-static void server_port_free(struct evdns_server_port *port);
-static void server_port_ready_callback(int fd, short events, void *arg);
-
-static int strtoint(const char *const str);
-
-#define last_error(sock) (errno)
-#define error_is_eagain(err) ((err) == EAGAIN)
-#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
-
-#define ISSPACE(c) isspace((int)(unsigned char)(c))
-#define ISDIGIT(c) isdigit((int)(unsigned char)(c))
-
-static const char *
-debug_ntoa(u32 address)
-{
- static char buf[32];
- u32 a = ntohl(address);
- evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
- (int)(u8)((a>>24)&0xff),
- (int)(u8)((a>>16)&0xff),
- (int)(u8)((a>>8 )&0xff),
- (int)(u8)((a )&0xff));
- return buf;
-}
-
-static evdns_debug_log_fn_type evdns_log_fn = NULL;
-
-void
-evdns_set_log_fn(evdns_debug_log_fn_type fn)
-{
- evdns_log_fn = fn;
-}
-
-#ifdef __GNUC__
-#define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3)))
-#else
-#define EVDNS_LOG_CHECK
-#endif
-
-static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
-static void
-_evdns_log(int warn, const char *fmt, ...)
-{
- va_list args;
- static char buf[512];
- if (!evdns_log_fn)
- return;
- va_start(args,fmt);
- evutil_vsnprintf(buf, sizeof(buf), fmt, args);
- buf[sizeof(buf)-1] = '\0';
- evdns_log_fn(warn, buf);
- va_end(args);
-}
-
-#define log _evdns_log
-
-/* This walks the list of inflight requests to find the */
-/* one with a matching transaction id. Returns NULL on */
-/* failure */
-static struct request *
-request_find_from_trans_id(u16 trans_id) {
- struct request *req = req_head, *const started_at = req_head;
-
- if (req) {
- do {
- if (req->trans_id == trans_id) return req;
- req = req->next;
- } while (req != started_at);
- }
-
- return NULL;
-}
-
-/* a libevent callback function which is called when a nameserver */
-/* has gone down and we want to test if it has came back to life yet */
-static void
-nameserver_prod_callback(int fd, short events, void *arg) {
- struct nameserver *const ns = (struct nameserver *) arg;
- (void)fd;
- (void)events;
-
- nameserver_send_probe(ns);
-}
-
-/* a libevent callback which is called when a nameserver probe (to see if */
-/* it has come back to life) times out. We increment the count of failed_times */
-/* and wait longer to send the next probe packet. */
-static void
-nameserver_probe_failed(struct nameserver *const ns) {
- const struct timeval * timeout;
- (void) evtimer_del(&ns->timeout_event);
- if (ns->state == 1) {
- /* This can happen if the nameserver acts in a way which makes us mark */
- /* it as bad and then starts sending good replies. */
- return;
- }
-
- timeout =
- &global_nameserver_timeouts[MIN(ns->failed_times,
- global_nameserver_timeouts_length - 1)];
- ns->failed_times++;
-
- evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
- if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) {
- log(EVDNS_LOG_WARN,
- "Error from libevent when adding timer event for %s",
- debug_ntoa(ns->address));
- /* ???? Do more? */
- }
-}
-
-/* called when a nameserver has been deemed to have failed. For example, too */
-/* many packets have timed out etc */
-static void
-nameserver_failed(struct nameserver *const ns, const char *msg) {
- struct request *req, *started_at;
- /* if this nameserver has already been marked as failed */
- /* then don't do anything */
- if (!ns->state) return;
-
- log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
- debug_ntoa(ns->address), msg);
- global_good_nameservers--;
- assert(global_good_nameservers >= 0);
- if (global_good_nameservers == 0) {
- log(EVDNS_LOG_WARN, "All nameservers have failed");
- }
-
- ns->state = 0;
- ns->failed_times = 1;
-
- evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
- if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
- log(EVDNS_LOG_WARN,
- "Error from libevent when adding timer event for %s",
- debug_ntoa(ns->address));
- /* ???? Do more? */
- }
-
- /* walk the list of inflight requests to see if any can be reassigned to */
- /* a different server. Requests in the waiting queue don't have a */
- /* nameserver assigned yet */
-
- /* if we don't have *any* good nameservers then there's no point */
- /* trying to reassign requests to one */
- if (!global_good_nameservers) return;
-
- req = req_head;
- started_at = req_head;
- if (req) {
- do {
- if (req->tx_count == 0 && req->ns == ns) {
- /* still waiting to go out, can be moved */
- /* to another server */
- req->ns = nameserver_pick();
- }
- req = req->next;
- } while (req != started_at);
- }
-}
-
-static void
-nameserver_up(struct nameserver *const ns) {
- if (ns->state) return;
- log(EVDNS_LOG_WARN, "Nameserver %s is back up",
- debug_ntoa(ns->address));
- evtimer_del(&ns->timeout_event);
- ns->state = 1;
- ns->failed_times = 0;
- ns->timedout = 0;
- global_good_nameservers++;
-}
-
-static void
-request_trans_id_set(struct request *const req, const u16 trans_id) {
- req->trans_id = trans_id;
- *((u16 *) req->request) = htons(trans_id);
-}
-
-/* Called to remove a request from a list and dealloc it. */
-/* head is a pointer to the head of the list it should be */
-/* removed from or NULL if the request isn't in a list. */
-static void
-request_finished(struct request *const req, struct request **head) {
- if (head) {
- if (req->next == req) {
- /* only item in the list */
- *head = NULL;
- } else {
- req->next->prev = req->prev;
- req->prev->next = req->next;
- if (*head == req) *head = req->next;
- }
- }
-
- log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
- (unsigned long) req);
- evtimer_del(&req->timeout_event);
-
- search_request_finished(req);
- global_requests_inflight--;
-
- if (!req->request_appended) {
- /* need to free the request data on it's own */
- free(req->request);
- } else {
- /* the request data is appended onto the header */
- /* so everything gets free()ed when we: */
- }
-
- free(req);
-
- evdns_requests_pump_waiting_queue();
-}
-
-/* This is called when a server returns a funny error code. */
-/* We try the request again with another server. */
-/* */
-/* return: */
-/* 0 ok */
-/* 1 failed/reissue is pointless */
-static int
-request_reissue(struct request *req) {
- const struct nameserver *const last_ns = req->ns;
- /* the last nameserver should have been marked as failing */
- /* by the caller of this function, therefore pick will try */
- /* not to return it */
- req->ns = nameserver_pick();
- if (req->ns == last_ns) {
- /* ... but pick did return it */
- /* not a lot of point in trying again with the */
- /* same server */
- return 1;
- }
-
- req->reissue_count++;
- req->tx_count = 0;
- req->transmit_me = 1;
-
- return 0;
-}
-
-/* this function looks for space on the inflight queue and promotes */
-/* requests from the waiting queue if it can. */
-static void
-evdns_requests_pump_waiting_queue(void) {
- while (global_requests_inflight < global_max_requests_inflight &&
- global_requests_waiting) {
- struct request *req;
- /* move a request from the waiting queue to the inflight queue */
- assert(req_waiting_head);
- if (req_waiting_head->next == req_waiting_head) {
- /* only one item in the queue */
- req = req_waiting_head;
- req_waiting_head = NULL;
- } else {
- req = req_waiting_head;
- req->next->prev = req->prev;
- req->prev->next = req->next;
- req_waiting_head = req->next;
- }
-
- global_requests_waiting--;
- global_requests_inflight++;
-
- req->ns = nameserver_pick();
- request_trans_id_set(req, transaction_id_pick());
-
- evdns_request_insert(req, &req_head);
- evdns_request_transmit(req);
- evdns_transmit();
- }
-}
-
-static void
-reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) {
- switch (req->request_type) {
- case TYPE_A:
- if (reply)
- req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
- reply->data.a.addrcount, ttl,
- reply->data.a.addresses,
- req->user_pointer);
- else
- req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
- return;
- case TYPE_PTR:
- if (reply) {
- char *name = reply->data.ptr.name;
- req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
- &name, req->user_pointer);
- } else {
- req->user_callback(err, 0, 0, 0, NULL,
- req->user_pointer);
- }
- return;
- case TYPE_AAAA:
- if (reply)
- req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
- reply->data.aaaa.addrcount, ttl,
- reply->data.aaaa.addresses,
- req->user_pointer);
- else
- req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
- return;
- }
- assert(0);
-}
-
-/* this processes a parsed reply packet */
-static void
-reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
- int error;
- static const int error_codes[] = {
- DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
- DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
- };
-
- if (flags & 0x020f || !reply || !reply->have_answer) {
- /* there was an error */
- if (flags & 0x0200) {
- error = DNS_ERR_TRUNCATED;
- } else {
- u16 error_code = (flags & 0x000f) - 1;
- if (error_code > 4) {
- error = DNS_ERR_UNKNOWN;
- } else {
- error = error_codes[error_code];
- }
- }
-
- switch(error) {
- case DNS_ERR_NOTIMPL:
- case DNS_ERR_REFUSED:
- /* we regard these errors as marking a bad nameserver */
- if (req->reissue_count < global_max_reissues) {
- char msg[64];
- evutil_snprintf(msg, sizeof(msg),
- "Bad response %d (%s)",
- error, evdns_err_to_string(error));
- nameserver_failed(req->ns, msg);
- if (!request_reissue(req)) return;
- }
- break;
- case DNS_ERR_SERVERFAILED:
- /* rcode 2 (servfailed) sometimes means "we
- * are broken" and sometimes (with some binds)
- * means "that request was very confusing."
- * Treat this as a timeout, not a failure.
- */
- log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
- "will allow the request to time out.",
- debug_ntoa(req->ns->address));
- break;
- default:
- /* we got a good reply from the nameserver */
- nameserver_up(req->ns);
- }
-
- if (req->search_state && req->request_type != TYPE_PTR) {
- /* if we have a list of domains to search in,
- * try the next one */
- if (!search_try_next(req)) {
- /* a new request was issued so this
- * request is finished and */
- /* the user callback will be made when
- * that request (or a */
- /* child of it) finishes. */
- request_finished(req, &req_head);
- return;
- }
- }
-
- /* all else failed. Pass the failure up */
- reply_callback(req, 0, error, NULL);
- request_finished(req, &req_head);
- } else {
- /* all ok, tell the user */
- reply_callback(req, ttl, 0, reply);
- nameserver_up(req->ns);
- request_finished(req, &req_head);
- }
-}
-
-static int
-name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
- int name_end = -1;
- int j = *idx;
- int ptr_count = 0;
-#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0)
-#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0)
-#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0)
-
- char *cp = name_out;
- const char *const end = name_out + name_out_len;
-
- /* Normally, names are a series of length prefixed strings terminated */
- /* with a length of 0 (the lengths are u8's < 63). */
- /* However, the length can start with a pair of 1 bits and that */
- /* means that the next 14 bits are a pointer within the current */
- /* packet. */
-
- for(;;) {
- u8 label_len;
- if (j >= length) return -1;
- GET8(label_len);
- if (!label_len) break;
- if (label_len & 0xc0) {
- u8 ptr_low;
- GET8(ptr_low);
- if (name_end < 0) name_end = j;
- j = (((int)label_len & 0x3f) << 8) + ptr_low;
- /* Make sure that the target offset is in-bounds. */
- if (j < 0 || j >= length) return -1;
- /* If we've jumped more times than there are characters in the
- * message, we must have a loop. */
- if (++ptr_count > length) return -1;
- continue;
- }
- if (label_len > 63) return -1;
- if (cp != name_out) {
- if (cp + 1 >= end) return -1;
- *cp++ = '.';
- }
- if (cp + label_len >= end) return -1;
- memcpy(cp, packet + j, label_len);
- cp += label_len;
- j += label_len;
- }
- if (cp >= end) return -1;
- *cp = '\0';
- if (name_end < 0)
- *idx = j;
- else
- *idx = name_end;
- return 0;
- err:
- return -1;
-}
-
-/* parses a raw request from a nameserver */
-static int
-reply_parse(u8 *packet, int length) {
- int j = 0, k = 0; /* index into packet */
- u16 _t; /* used by the macros */
- u32 _t32; /* used by the macros */
- char tmp_name[256], cmp_name[256]; /* used by the macros */
-
- u16 trans_id, questions, answers, authority, additional, datalength;
- u16 flags = 0;
- u32 ttl, ttl_r = 0xffffffff;
- struct reply reply;
- struct request *req = NULL;
- unsigned int i;
-
- GET16(trans_id);
- GET16(flags);
- GET16(questions);
- GET16(answers);
- GET16(authority);
- GET16(additional);
- (void) authority; /* suppress "unused variable" warnings. */
- (void) additional; /* suppress "unused variable" warnings. */
-
- req = request_find_from_trans_id(trans_id);
- if (!req) return -1;
-
- memset(&reply, 0, sizeof(reply));
-
- /* If it's not an answer, it doesn't correspond to any request. */
- if (!(flags & 0x8000)) return -1; /* must be an answer */
- if (flags & 0x020f) {
- /* there was an error */
- goto err;
- }
- /* if (!answers) return; */ /* must have an answer of some form */
-
- /* This macro skips a name in the DNS reply. */
-#define SKIP_NAME \
- do { tmp_name[0] = '\0'; \
- if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
- goto err; \
- } while(0)
-#define TEST_NAME \
- do { tmp_name[0] = '\0'; \
- cmp_name[0] = '\0'; \
- k = j; \
- if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
- goto err; \
- if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0) \
- goto err; \
- if (memcmp(tmp_name, cmp_name, strlen (tmp_name)) != 0) \
- return (-1); /* we ignore mismatching names */ \
- } while(0)
-
- reply.type = req->request_type;
-
- /* skip over each question in the reply */
- for (i = 0; i < questions; ++i) {
- /* the question looks like
- * <label:name><u16:type><u16:class>
- */
- TEST_NAME;
- j += 4;
- if (j > length) goto err;
- }
-
- /* now we have the answer section which looks like
- * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
- */
-
- for (i = 0; i < answers; ++i) {
- u16 type, class;
-
- SKIP_NAME;
- GET16(type);
- GET16(class);
- GET32(ttl);
- GET16(datalength);
-
- if (type == TYPE_A && class == CLASS_INET) {
- int addrcount, addrtocopy;
- if (req->request_type != TYPE_A) {
- j += datalength; continue;
- }
- if ((datalength & 3) != 0) /* not an even number of As. */
- goto err;
- addrcount = datalength >> 2;
- addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
-
- ttl_r = MIN(ttl_r, ttl);
- /* we only bother with the first four addresses. */
- if (j + 4*addrtocopy > length) goto err;
- memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
- packet + j, 4*addrtocopy);
- j += 4*addrtocopy;
- reply.data.a.addrcount += addrtocopy;
- reply.have_answer = 1;
- if (reply.data.a.addrcount == MAX_ADDRS) break;
- } else if (type == TYPE_PTR && class == CLASS_INET) {
- if (req->request_type != TYPE_PTR) {
- j += datalength; continue;
- }
- if (name_parse(packet, length, &j, reply.data.ptr.name,
- sizeof(reply.data.ptr.name))<0)
- goto err;
- ttl_r = MIN(ttl_r, ttl);
- reply.have_answer = 1;
- break;
- } else if (type == TYPE_AAAA && class == CLASS_INET) {
- int addrcount, addrtocopy;
- if (req->request_type != TYPE_AAAA) {
- j += datalength; continue;
- }
- if ((datalength & 15) != 0) /* not an even number of AAAAs. */
- goto err;
- addrcount = datalength >> 4; /* each address is 16 bytes long */
- addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
- ttl_r = MIN(ttl_r, ttl);
-
- /* we only bother with the first four addresses. */
- if (j + 16*addrtocopy > length) goto err;
- memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
- packet + j, 16*addrtocopy);
- reply.data.aaaa.addrcount += addrtocopy;
- j += 16*addrtocopy;
- reply.have_answer = 1;
- if (reply.data.aaaa.addrcount == MAX_ADDRS) break;
- } else {
- /* skip over any other type of resource */
- j += datalength;
- }
- }
-
- reply_handle(req, flags, ttl_r, &reply);
- return 0;
- err:
- if (req)
- reply_handle(req, flags, 0, NULL);
- return -1;
-}
-
-/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
-/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
-/* callback. */
-static int
-request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
-{
- int j = 0; /* index into packet */
- u16 _t; /* used by the macros */
- char tmp_name[256]; /* used by the macros */
-
- int i;
- u16 trans_id, flags, questions, answers, authority, additional;
- struct server_request *server_req = NULL;
-
- /* Get the header fields */
- GET16(trans_id);
- GET16(flags);
- GET16(questions);
- GET16(answers);
- GET16(authority);
- GET16(additional);
-
- if (flags & 0x8000) return -1; /* Must not be an answer. */
- flags &= 0x0110; /* Only RD and CD get preserved. */
-
- server_req = malloc(sizeof(struct server_request));
- if (server_req == NULL) return -1;
- memset(server_req, 0, sizeof(struct server_request));
-
- server_req->trans_id = trans_id;
- memcpy(&server_req->addr, addr, addrlen);
- server_req->addrlen = addrlen;
-
- server_req->base.flags = flags;
- server_req->base.nquestions = 0;
- server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions);
- if (server_req->base.questions == NULL)
- goto err;
-
- for (i = 0; i < questions; ++i) {
- u16 type, class;
- struct evdns_server_question *q;
- int namelen;
- if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
- goto err;
- GET16(type);
- GET16(class);
- namelen = strlen(tmp_name);
- q = malloc(sizeof(struct evdns_server_question) + namelen);
- if (!q)
- goto err;
- q->type = type;
- q->dns_question_class = class;
- memcpy(q->name, tmp_name, namelen+1);
- server_req->base.questions[server_req->base.nquestions++] = q;
- }
-
- /* Ignore answers, authority, and additional. */
-
- server_req->port = port;
- port->refcnt++;
-
- /* Only standard queries are supported. */
- if (flags & 0x7800) {
- evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
- return -1;
- }
-
- port->user_callback(&(server_req->base), port->user_data);
-
- return 0;
-err:
- if (server_req) {
- if (server_req->base.questions) {
- for (i = 0; i < server_req->base.nquestions; ++i)
- free(server_req->base.questions[i]);
- free(server_req->base.questions);
- }
- free(server_req);
- }
- return -1;
-
-#undef SKIP_NAME
-#undef GET32
-#undef GET16
-#undef GET8
-}
-
-static u16
-default_transaction_id_fn(void)
-{
- u16 trans_id;
-#ifdef DNS_USE_CPU_CLOCK_FOR_ID
- struct timespec ts;
- static int clkid = -1;
- if (clkid == -1) {
- clkid = CLOCK_REALTIME;
-#ifdef CLOCK_MONOTONIC
- if (clock_gettime(CLOCK_MONOTONIC, &ts) != -1)
- clkid = CLOCK_MONOTONIC;
-#endif
- }
- if (clock_gettime(clkid, &ts) == -1)
- event_err(1, "clock_gettime");
- trans_id = ts.tv_nsec & 0xffff;
-#endif
-
-#ifdef DNS_USE_FTIME_FOR_ID
- struct _timeb tb;
- _ftime(&tb);
- trans_id = tb.millitm & 0xffff;
-#endif
-
-#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
- struct timeval tv;
- evutil_gettimeofday(&tv, NULL);
- trans_id = tv.tv_usec & 0xffff;
-#endif
-
-#ifdef DNS_USE_OPENSSL_FOR_ID
- if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
- /* in the case that the RAND call fails we back */
- /* down to using gettimeofday. */
- /*
- struct timeval tv;
- evutil_gettimeofday(&tv, NULL);
- trans_id = tv.tv_usec & 0xffff;
- */
- abort();
- }
-#endif
- return trans_id;
-}
-
-static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
-
-void
-evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
-{
- if (fn)
- trans_id_function = fn;
- else
- trans_id_function = default_transaction_id_fn;
-}
-
-/* Try to choose a strong transaction id which isn't already in flight */
-static u16
-transaction_id_pick(void) {
- for (;;) {
- const struct request *req = req_head, *started_at;
- u16 trans_id = trans_id_function();
-
- if (trans_id == 0xffff) continue;
- /* now check to see if that id is already inflight */
- req = started_at = req_head;
- if (req) {
- do {
- if (req->trans_id == trans_id) break;
- req = req->next;
- } while (req != started_at);
- }
- /* we didn't find it, so this is a good id */
- if (req == started_at) return trans_id;
- }
-}
-
-/* choose a namesever to use. This function will try to ignore */
-/* nameservers which we think are down and load balance across the rest */
-/* by updating the server_head global each time. */
-static struct nameserver *
-nameserver_pick(void) {
- struct nameserver *started_at = server_head, *picked;
- if (!server_head) return NULL;
-
- /* if we don't have any good nameservers then there's no */
- /* point in trying to find one. */
- if (!global_good_nameservers) {
- server_head = server_head->next;
- return server_head;
- }
-
- /* remember that nameservers are in a circular list */
- for (;;) {
- if (server_head->state) {
- /* we think this server is currently good */
- picked = server_head;
- server_head = server_head->next;
- return picked;
- }
-
- server_head = server_head->next;
- if (server_head == started_at) {
- /* all the nameservers seem to be down */
- /* so we just return this one and hope for the */
- /* best */
- assert(global_good_nameservers == 0);
- picked = server_head;
- server_head = server_head->next;
- return picked;
- }
- }
-}
-
-/* this is called when a namesever socket is ready for reading */
-static void
-nameserver_read(struct nameserver *ns) {
- u8 packet[1500];
-
- for (;;) {
- const int r = recv(ns->socket, packet, sizeof(packet), 0);
- if (r < 0) {
- int err = last_error(ns->socket);
- if (error_is_eagain(err)) return;
- nameserver_failed(ns, strerror(err));
- return;
- }
- ns->timedout = 0;
- reply_parse(packet, r);
- }
-}
-
-/* Read a packet from a DNS client on a server port s, parse it, and */
-/* act accordingly. */
-static void
-server_port_read(struct evdns_server_port *s) {
- u8 packet[1500];
- struct sockaddr_storage addr;
- socklen_t addrlen;
- int r;
-
- for (;;) {
- addrlen = sizeof(struct sockaddr_storage);
- r = recvfrom(s->socket, packet, sizeof(packet), 0,
- (struct sockaddr*) &addr, &addrlen);
- if (r < 0) {
- int err = last_error(s->socket);
- if (error_is_eagain(err)) return;
- log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
- strerror(err), err);
- return;
- }
- request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
- }
-}
-
-/* Try to write all pending replies on a given DNS server port. */
-static void
-server_port_flush(struct evdns_server_port *port)
-{
- while (port->pending_replies) {
- struct server_request *req = port->pending_replies;
- int r = sendto(port->socket, req->response, req->response_len, 0,
- (struct sockaddr*) &req->addr, req->addrlen);
- if (r < 0) {
- int err = last_error(port->socket);
- if (error_is_eagain(err))
- return;
- log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err);
- }
- if (server_request_free(req)) {
- /* we released the last reference to req->port. */
- return;
- }
- }
-
- /* We have no more pending requests; stop listening for 'writeable' events. */
- (void) event_del(&port->event);
- event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
- server_port_ready_callback, port);
- if (event_add(&port->event, NULL) < 0) {
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
- /* ???? Do more? */
- }
-}
-
-/* set if we are waiting for the ability to write to this server. */
-/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
-/* we stop these events. */
-static void
-nameserver_write_waiting(struct nameserver *ns, char waiting) {
- if (ns->write_waiting == waiting) return;
-
- ns->write_waiting = waiting;
- (void) event_del(&ns->event);
- event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
- nameserver_ready_callback, ns);
- if (event_add(&ns->event, NULL) < 0) {
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
- debug_ntoa(ns->address));
- /* ???? Do more? */
- }
-}
-
-/* a callback function. Called by libevent when the kernel says that */
-/* a nameserver socket is ready for writing or reading */
-static void
-nameserver_ready_callback(int fd, short events, void *arg) {
- struct nameserver *ns = (struct nameserver *) arg;
- (void)fd;
-
- if (events & EV_WRITE) {
- ns->choked = 0;
- if (!evdns_transmit()) {
- nameserver_write_waiting(ns, 0);
- }
- }
- if (events & EV_READ) {
- nameserver_read(ns);
- }
-}
-
-/* a callback function. Called by libevent when the kernel says that */
-/* a server socket is ready for writing or reading. */
-static void
-server_port_ready_callback(int fd, short events, void *arg) {
- struct evdns_server_port *port = (struct evdns_server_port *) arg;
- (void) fd;
-
- if (events & EV_WRITE) {
- port->choked = 0;
- server_port_flush(port);
- }
- if (events & EV_READ) {
- server_port_read(port);
- }
-}
-
-/* This is an inefficient representation; only use it via the dnslabel_table_*
- * functions, so that is can be safely replaced with something smarter later. */
-#define MAX_LABELS 128
-/* Structures used to implement name compression */
-struct dnslabel_entry { char *v; off_t pos; };
-struct dnslabel_table {
- int n_labels; /* number of current entries */
- /* map from name to position in message */
- struct dnslabel_entry labels[MAX_LABELS];
-};
-
-/* Initialize dnslabel_table. */
-static void
-dnslabel_table_init(struct dnslabel_table *table)
-{
- table->n_labels = 0;
-}
-
-/* Free all storage held by table, but not the table itself. */
-static void
-dnslabel_clear(struct dnslabel_table *table)
-{
- int i;
- for (i = 0; i < table->n_labels; ++i)
- free(table->labels[i].v);
- table->n_labels = 0;
-}
-
-/* return the position of the label in the current message, or -1 if the label */
-/* hasn't been used yet. */
-static int
-dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
-{
- int i;
- for (i = 0; i < table->n_labels; ++i) {
- if (!strcmp(label, table->labels[i].v))
- return table->labels[i].pos;
- }
- return -1;
-}
-
-/* remember that we've used the label at position pos */
-static int
-dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
-{
- char *v;
- int p;
- if (table->n_labels == MAX_LABELS)
- return (-1);
- v = strdup(label);
- if (v == NULL)
- return (-1);
- p = table->n_labels++;
- table->labels[p].v = v;
- table->labels[p].pos = pos;
-
- return (0);
-}
-
-/* Converts a string to a length-prefixed set of DNS labels, starting */
-/* at buf[j]. name and buf must not overlap. name_len should be the length */
-/* of name. table is optional, and is used for compression. */
-/* */
-/* Input: abc.def */
-/* Output: <3>abc<3>def<0> */
-/* */
-/* Returns the first index after the encoded name, or negative on error. */
-/* -1 label was > 63 bytes */
-/* -2 name too long to fit in buffer. */
-/* */
-static off_t
-dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
- const char *name, const int name_len,
- struct dnslabel_table *table) {
- const char *end = name + name_len;
- int ref = 0;
- u16 _t;
-
-#define APPEND16(x) do { \
- if (j + 2 > (off_t)buf_len) \
- goto overflow; \
- _t = htons(x); \
- memcpy(buf + j, &_t, 2); \
- j += 2; \
- } while (0)
-#define APPEND32(x) do { \
- if (j + 4 > (off_t)buf_len) \
- goto overflow; \
- _t32 = htonl(x); \
- memcpy(buf + j, &_t32, 4); \
- j += 4; \
- } while (0)
-
- if (name_len > 255) return -2;
-
- for (;;) {
- const char *const start = name;
- if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
- APPEND16(ref | 0xc000);
- return j;
- }
- name = strchr(name, '.');
- if (!name) {
- const unsigned int label_len = end - start;
- if (label_len > 63) return -1;
- if ((size_t)(j+label_len+1) > buf_len) return -2;
- if (table) dnslabel_table_add(table, start, j);
- buf[j++] = label_len;
-
- memcpy(buf + j, start, end - start);
- j += end - start;
- break;
- } else {
- /* append length of the label. */
- const unsigned int label_len = name - start;
- if (label_len > 63) return -1;
- if ((size_t)(j+label_len+1) > buf_len) return -2;
- if (table) dnslabel_table_add(table, start, j);
- buf[j++] = label_len;
-
- memcpy(buf + j, start, name - start);
- j += name - start;
- /* hop over the '.' */
- name++;
- }
- }
-
- /* the labels must be terminated by a 0. */
- /* It's possible that the name ended in a . */
- /* in which case the zero is already there */
- if (!j || buf[j-1]) buf[j++] = 0;
- return j;
- overflow:
- return (-2);
-}
-
-/* Finds the length of a dns request for a DNS name of the given */
-/* length. The actual request may be smaller than the value returned */
-/* here */
-static int
-evdns_request_len(const int name_len) {
- return 96 + /* length of the DNS standard header */
- name_len + 2 +
- 4; /* space for the resource type */
-}
-
-/* build a dns request packet into buf. buf should be at least as long */
-/* as evdns_request_len told you it should be. */
-/* */
-/* Returns the amount of space used. Negative on error. */
-static int
-evdns_request_data_build(const char *const name, const int name_len,
- const u16 trans_id, const u16 type, const u16 class,
- u8 *const buf, size_t buf_len) {
- off_t j = 0; /* current offset into buf */
- u16 _t; /* used by the macros */
-
- APPEND16(trans_id);
- APPEND16(0x0100); /* standard query, recusion needed */
- APPEND16(1); /* one question */
- APPEND16(0); /* no answers */
- APPEND16(0); /* no authority */
- APPEND16(0); /* no additional */
-
- j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
- if (j < 0) {
- return (int)j;
- }
-
- APPEND16(type);
- APPEND16(class);
-
- return (int)j;
- overflow:
- return (-1);
-}
-
-/* exported function */
-struct evdns_server_port *
-evdns_add_server_port(int s, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
-{
- struct evdns_server_port *port;
- if (!(port = malloc(sizeof(struct evdns_server_port))))
- return NULL;
- memset(port, 0, sizeof(struct evdns_server_port));
-
- assert(!is_tcp); /* TCP sockets not yet implemented */
- port->socket = s;
- port->refcnt = 1;
- port->choked = 0;
- port->closing = 0;
- port->user_callback = cb;
- port->user_data = user_data;
- port->pending_replies = NULL;
-
- event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
- server_port_ready_callback, port);
- event_add(&port->event, NULL); /* check return. */
- return port;
-}
-
-/* exported function */
-void
-evdns_close_server_port(struct evdns_server_port *port)
-{
- if (--port->refcnt == 0)
- server_port_free(port);
- port->closing = 1;
-}
-
-/* exported function */
-int
-evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
-{
- struct server_request *req = TO_SERVER_REQUEST(_req);
- struct server_reply_item **itemp, *item;
- int *countp;
-
- if (req->response) /* have we already answered? */
- return (-1);
-
- switch (section) {
- case EVDNS_ANSWER_SECTION:
- itemp = &req->answer;
- countp = &req->n_answer;
- break;
- case EVDNS_AUTHORITY_SECTION:
- itemp = &req->authority;
- countp = &req->n_authority;
- break;
- case EVDNS_ADDITIONAL_SECTION:
- itemp = &req->additional;
- countp = &req->n_additional;
- break;
- default:
- return (-1);
- }
- while (*itemp) {
- itemp = &((*itemp)->next);
- }
- item = malloc(sizeof(struct server_reply_item));
- if (!item)
- return -1;
- item->next = NULL;
- if (!(item->name = strdup(name))) {
- free(item);
- return -1;
- }
- item->type = type;
- item->dns_question_class = class;
- item->ttl = ttl;
- item->is_name = is_name != 0;
- item->datalen = 0;
- item->data = NULL;
- if (data) {
- if (item->is_name) {
- if (!(item->data = strdup(data))) {
- free(item->name);
- free(item);
- return -1;
- }
- item->datalen = (u16)-1;
- } else {
- if (!(item->data = malloc(datalen))) {
- free(item->name);
- free(item);
- return -1;
- }
- item->datalen = datalen;
- memcpy(item->data, data, datalen);
- }
- }
-
- *itemp = item;
- ++(*countp);
- return 0;
-}
-
-/* exported function */
-int
-evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
-{
- return evdns_server_request_add_reply(
- req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
- ttl, n*4, 0, addrs);
-}
-
-/* exported function */
-int
-evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
-{
- return evdns_server_request_add_reply(
- req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
- ttl, n*16, 0, addrs);
-}
-
-/* exported function */
-int
-evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
-{
- u32 a;
- char buf[32];
- assert(in || inaddr_name);
- assert(!(in && inaddr_name));
- if (in) {
- a = ntohl(in->s_addr);
- evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
- (int)(u8)((a )&0xff),
- (int)(u8)((a>>8 )&0xff),
- (int)(u8)((a>>16)&0xff),
- (int)(u8)((a>>24)&0xff));
- inaddr_name = buf;
- }
- return evdns_server_request_add_reply(
- req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
- ttl, -1, 1, hostname);
-}
-
-/* exported function */
-int
-evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
-{
- return evdns_server_request_add_reply(
- req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
- ttl, -1, 1, cname);
-}
-
-
-static int
-evdns_server_request_format_response(struct server_request *req, int err)
-{
- unsigned char buf[1500];
- size_t buf_len = sizeof(buf);
- off_t j = 0, r;
- u16 _t;
- u32 _t32;
- int i;
- u16 flags;
- struct dnslabel_table table;
-
- if (err < 0 || err > 15) return -1;
-
- /* Set response bit and error code; copy OPCODE and RD fields from
- * question; copy RA and AA if set by caller. */
- flags = req->base.flags;
- flags |= (0x8000 | err);
-
- dnslabel_table_init(&table);
- APPEND16(req->trans_id);
- APPEND16(flags);
- APPEND16(req->base.nquestions);
- APPEND16(req->n_answer);
- APPEND16(req->n_authority);
- APPEND16(req->n_additional);
-
- /* Add questions. */
- for (i=0; i < req->base.nquestions; ++i) {
- const char *s = req->base.questions[i]->name;
- j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
- if (j < 0) {
- dnslabel_clear(&table);
- return (int) j;
- }
- APPEND16(req->base.questions[i]->type);
- APPEND16(req->base.questions[i]->dns_question_class);
- }
-
- /* Add answer, authority, and additional sections. */
- for (i=0; i<3; ++i) {
- struct server_reply_item *item;
- if (i==0)
- item = req->answer;
- else if (i==1)
- item = req->authority;
- else
- item = req->additional;
- while (item) {
- r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
- if (r < 0)
- goto overflow;
- j = r;
-
- APPEND16(item->type);
- APPEND16(item->dns_question_class);
- APPEND32(item->ttl);
- if (item->is_name) {
- off_t len_idx = j, name_start;
- j += 2;
- name_start = j;
- r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
- if (r < 0)
- goto overflow;
- j = r;
- _t = htons( (short) (j-name_start) );
- memcpy(buf+len_idx, &_t, 2);
- } else {
- APPEND16(item->datalen);
- if (j+item->datalen > (off_t)buf_len)
- goto overflow;
- memcpy(buf+j, item->data, item->datalen);
- j += item->datalen;
- }
- item = item->next;
- }
- }
-
- if (j > 512) {
-overflow:
- j = 512;
- buf[3] |= 0x02; /* set the truncated bit. */
- }
-
- req->response_len = j;
-
- if (!(req->response = malloc(req->response_len))) {
- server_request_free_answers(req);
- dnslabel_clear(&table);
- return (-1);
- }
- memcpy(req->response, buf, req->response_len);
- server_request_free_answers(req);
- dnslabel_clear(&table);
- return (0);
-}
-
-/* exported function */
-int
-evdns_server_request_respond(struct evdns_server_request *_req, int err)
-{
- struct server_request *req = TO_SERVER_REQUEST(_req);
- struct evdns_server_port *port = req->port;
- int r;
- if (!req->response) {
- if ((r = evdns_server_request_format_response(req, err))<0)
- return r;
- }
-
- r = sendto(port->socket, req->response, req->response_len, 0,
- (struct sockaddr*) &req->addr, req->addrlen);
- if (r<0) {
- int sock_err = last_error(port->socket);
- if (! error_is_eagain(sock_err))
- return -1;
-
- if (port->pending_replies) {
- req->prev_pending = port->pending_replies->prev_pending;
- req->next_pending = port->pending_replies;
- req->prev_pending->next_pending =
- req->next_pending->prev_pending = req;
- } else {
- req->prev_pending = req->next_pending = req;
- port->pending_replies = req;
- port->choked = 1;
-
- (void) event_del(&port->event);
- event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
-
- if (event_add(&port->event, NULL) < 0) {
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
- }
-
- }
-
- return 1;
- }
- if (server_request_free(req))
- return 0;
-
- if (port->pending_replies)
- server_port_flush(port);
-
- return 0;
-}
-
-/* Free all storage held by RRs in req. */
-static void
-server_request_free_answers(struct server_request *req)
-{
- struct server_reply_item *victim, *next, **list;
- int i;
- for (i = 0; i < 3; ++i) {
- if (i==0)
- list = &req->answer;
- else if (i==1)
- list = &req->authority;
- else
- list = &req->additional;
-
- victim = *list;
- while (victim) {
- next = victim->next;
- free(victim->name);
- if (victim->data)
- free(victim->data);
- free(victim);
- victim = next;
- }
- *list = NULL;
- }
-}
-
-/* Free all storage held by req, and remove links to it. */
-/* return true iff we just wound up freeing the server_port. */
-static int
-server_request_free(struct server_request *req)
-{
- int i, rc=1;
- if (req->base.questions) {
- for (i = 0; i < req->base.nquestions; ++i)
- free(req->base.questions[i]);
- free(req->base.questions);
- }
-
- if (req->port) {
- if (req->port->pending_replies == req) {
- if (req->next_pending)
- req->port->pending_replies = req->next_pending;
- else
- req->port->pending_replies = NULL;
- }
- rc = --req->port->refcnt;
- }
-
- if (req->response) {
- free(req->response);
- }
-
- server_request_free_answers(req);
-
- if (req->next_pending && req->next_pending != req) {
- req->next_pending->prev_pending = req->prev_pending;
- req->prev_pending->next_pending = req->next_pending;
- }
-
- if (rc == 0) {
- server_port_free(req->port);
- free(req);
- return (1);
- }
- free(req);
- return (0);
-}
-
-/* Free all storage held by an evdns_server_port. Only called when */
-static void
-server_port_free(struct evdns_server_port *port)
-{
- assert(port);
- assert(!port->refcnt);
- assert(!port->pending_replies);
- if (port->socket > 0) {
- CLOSE_SOCKET(port->socket);
- port->socket = -1;
- }
- (void) event_del(&port->event);
- /* XXXX actually free the port? -NM */
-}
-
-/* exported function */
-int
-evdns_server_request_drop(struct evdns_server_request *_req)
-{
- struct server_request *req = TO_SERVER_REQUEST(_req);
- server_request_free(req);
- return 0;
-}
-
-/* exported function */
-int
-evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
-{
- struct server_request *req = TO_SERVER_REQUEST(_req);
- if (addr_len < (int)req->addrlen)
- return -1;
- memcpy(sa, &(req->addr), req->addrlen);
- return req->addrlen;
-}
-
-#undef APPEND16
-#undef APPEND32
-
-/* this is a libevent callback function which is called when a request */
-/* has timed out. */
-static void
-evdns_request_timeout_callback(int fd, short events, void *arg) {
- struct request *const req = (struct request *) arg;
- (void) fd;
- (void) events;
-
- log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
-
- req->ns->timedout++;
- if (req->ns->timedout > global_max_nameserver_timeout) {
- req->ns->timedout = 0;
- nameserver_failed(req->ns, "request timed out.");
- }
-
- (void) evtimer_del(&req->timeout_event);
- if (req->tx_count >= global_max_retransmits) {
- /* this request has failed */
- reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
- request_finished(req, &req_head);
- } else {
- /* retransmit it */
- evdns_request_transmit(req);
- }
-}
-
-/* try to send a request to a given server. */
-/* */
-/* return: */
-/* 0 ok */
-/* 1 temporary failure */
-/* 2 other failure */
-static int
-evdns_request_transmit_to(struct request *req, struct nameserver *server) {
- const int r = send(server->socket, req->request, req->request_len, 0);
- if (r < 0) {
- int err = last_error(server->socket);
- if (error_is_eagain(err)) return 1;
- nameserver_failed(req->ns, strerror(err));
- return 2;
- } else if (r != (int)req->request_len) {
- return 1; /* short write */
- } else {
- return 0;
- }
-}
-
-/* try to send a request, updating the fields of the request */
-/* as needed */
-/* */
-/* return: */
-/* 0 ok */
-/* 1 failed */
-static int
-evdns_request_transmit(struct request *req) {
- int retcode = 0, r;
-
- /* if we fail to send this packet then this flag marks it */
- /* for evdns_transmit */
- req->transmit_me = 1;
- if (req->trans_id == 0xffff) abort();
-
- if (req->ns->choked) {
- /* don't bother trying to write to a socket */
- /* which we have had EAGAIN from */
- return 1;
- }
-
- r = evdns_request_transmit_to(req, req->ns);
- switch (r) {
- case 1:
- /* temp failure */
- req->ns->choked = 1;
- nameserver_write_waiting(req->ns, 1);
- return 1;
- case 2:
- /* failed in some other way */
- retcode = 1;
- /* fall through */
- default:
- /* all ok */
- log(EVDNS_LOG_DEBUG,
- "Setting timeout for request %lx", (unsigned long) req);
- evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
- if (evtimer_add(&req->timeout_event, &global_timeout) < 0) {
- log(EVDNS_LOG_WARN,
- "Error from libevent when adding timer for request %lx",
- (unsigned long) req);
- /* ???? Do more? */
- }
- req->tx_count++;
- req->transmit_me = 0;
- return retcode;
- }
-}
-
-static void
-nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
- struct nameserver *const ns = (struct nameserver *) arg;
- (void) type;
- (void) count;
- (void) ttl;
- (void) addresses;
-
- if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
- /* this is a good reply */
- nameserver_up(ns);
- } else nameserver_probe_failed(ns);
-}
-
-static void
-nameserver_send_probe(struct nameserver *const ns) {
- struct request *req;
- /* here we need to send a probe to a given nameserver */
- /* in the hope that it is up now. */
-
- log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address));
-
- req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
- if (!req) return;
- /* we force this into the inflight queue no matter what */
- request_trans_id_set(req, transaction_id_pick());
- req->ns = ns;
- request_submit(req);
-}
-
-/* returns: */
-/* 0 didn't try to transmit anything */
-/* 1 tried to transmit something */
-static int
-evdns_transmit(void) {
- char did_try_to_transmit = 0;
-
- if (req_head) {
- struct request *const started_at = req_head, *req = req_head;
- /* first transmit all the requests which are currently waiting */
- do {
- if (req->transmit_me) {
- did_try_to_transmit = 1;
- evdns_request_transmit(req);
- }
-
- req = req->next;
- } while (req != started_at);
- }
-
- return did_try_to_transmit;
-}
-
-/* exported function */
-int
-evdns_count_nameservers(void)
-{
- const struct nameserver *server = server_head;
- int n = 0;
- if (!server)
- return 0;
- do {
- ++n;
- server = server->next;
- } while (server != server_head);
- return n;
-}
-
-/* exported function */
-int
-evdns_clear_nameservers_and_suspend(void)
-{
- struct nameserver *server = server_head, *started_at = server_head;
- struct request *req = req_head, *req_started_at = req_head;
-
- if (!server)
- return 0;
- while (1) {
- struct nameserver *next = server->next;
- (void) event_del(&server->event);
- if (evtimer_initialized(&server->timeout_event))
- (void) evtimer_del(&server->timeout_event);
- if (server->socket >= 0)
- CLOSE_SOCKET(server->socket);
- free(server);
- if (next == started_at)
- break;
- server = next;
- }
- server_head = NULL;
- global_good_nameservers = 0;
-
- while (req) {
- struct request *next = req->next;
- req->tx_count = req->reissue_count = 0;
- req->ns = NULL;
- /* ???? What to do about searches? */
- (void) evtimer_del(&req->timeout_event);
- req->trans_id = 0;
- req->transmit_me = 0;
-
- global_requests_waiting++;
- evdns_request_insert(req, &req_waiting_head);
- /* We want to insert these suspended elements at the front of
- * the waiting queue, since they were pending before any of
- * the waiting entries were added. This is a circular list,
- * so we can just shift the start back by one.*/
- req_waiting_head = req_waiting_head->prev;
-
- if (next == req_started_at)
- break;
- req = next;
- }
- req_head = NULL;
- global_requests_inflight = 0;
-
- return 0;
-}
-
-
-/* exported function */
-int
-evdns_resume(void)
-{
- evdns_requests_pump_waiting_queue();
- return 0;
-}
-
-static int
-_evdns_nameserver_add_impl(unsigned long int address, int port) {
- /* first check to see if we already have this nameserver */
-
- const struct nameserver *server = server_head, *const started_at = server_head;
- struct nameserver *ns;
- struct sockaddr_in sin;
- int err = 0;
- if (server) {
- do {
- if (server->address == address) return 3;
- server = server->next;
- } while (server != started_at);
- }
-
- ns = (struct nameserver *) malloc(sizeof(struct nameserver));
- if (!ns) return -1;
-
- memset(ns, 0, sizeof(struct nameserver));
-
- ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
- if (ns->socket < 0) { err = 1; goto out1; }
- evutil_make_socket_nonblocking(ns->socket);
- sin.sin_addr.s_addr = address;
- sin.sin_port = htons(port);
- sin.sin_family = AF_INET;
- if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
- err = 2;
- goto out2;
- }
-
- ns->address = address;
- ns->state = 1;
- event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
- if (event_add(&ns->event, NULL) < 0) {
- err = 2;
- goto out2;
- }
-
- log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address));
-
- /* insert this nameserver into the list of them */
- if (!server_head) {
- ns->next = ns->prev = ns;
- server_head = ns;
- } else {
- ns->next = server_head->next;
- ns->prev = server_head;
- server_head->next = ns;
- if (server_head->prev == server_head) {
- server_head->prev = ns;
- }
- }
-
- global_good_nameservers++;
-
- return 0;
-
-out2:
- CLOSE_SOCKET(ns->socket);
-out1:
- free(ns);
- log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err);
- return err;
-}
-
-/* exported function */
-int
-evdns_nameserver_add(unsigned long int address) {
- return _evdns_nameserver_add_impl(address, 53);
-}
-
-/* exported function */
-int
-evdns_nameserver_ip_add(const char *ip_as_string) {
- struct in_addr ina;
- int port;
- char buf[20];
- const char *cp;
- cp = strchr(ip_as_string, ':');
- if (! cp) {
- cp = ip_as_string;
- port = 53;
- } else {
- port = strtoint(cp+1);
- if (port < 0 || port > 65535) {
- return 4;
- }
- if ((cp-ip_as_string) >= (int)sizeof(buf)) {
- return 4;
- }
- memcpy(buf, ip_as_string, cp-ip_as_string);
- buf[cp-ip_as_string] = '\0';
- cp = buf;
- }
- if (!inet_aton(cp, &ina)) {
- return 4;
- }
- return _evdns_nameserver_add_impl(ina.s_addr, port);
-}
-
-/* insert into the tail of the queue */
-static void
-evdns_request_insert(struct request *req, struct request **head) {
- if (!*head) {
- *head = req;
- req->next = req->prev = req;
- return;
- }
-
- req->prev = (*head)->prev;
- req->prev->next = req;
- req->next = *head;
- (*head)->prev = req;
-}
-
-static int
-string_num_dots(const char *s) {
- int count = 0;
- while ((s = strchr(s, '.'))) {
- s++;
- count++;
- }
- return count;
-}
-
-static struct request *
-request_new(int type, const char *name, int flags,
- evdns_callback_type callback, void *user_ptr) {
- const char issuing_now =
- (global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
-
- const int name_len = strlen(name);
- const int request_max_len = evdns_request_len(name_len);
- const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
- /* the request data is alloced in a single block with the header */
- struct request *const req =
- (struct request *) malloc(sizeof(struct request) + request_max_len);
- int rlen;
- (void) flags;
-
- if (!req) return NULL;
- memset(req, 0, sizeof(struct request));
-
- /* request data lives just after the header */
- req->request = ((u8 *) req) + sizeof(struct request);
- /* denotes that the request data shouldn't be free()ed */
- req->request_appended = 1;
- rlen = evdns_request_data_build(name, name_len, trans_id,
- type, CLASS_INET, req->request, request_max_len);
- if (rlen < 0)
- goto err1;
- req->request_len = rlen;
- req->trans_id = trans_id;
- req->tx_count = 0;
- req->request_type = type;
- req->user_pointer = user_ptr;
- req->user_callback = callback;
- req->ns = issuing_now ? nameserver_pick() : NULL;
- req->next = req->prev = NULL;
-
- return req;
-err1:
- free(req);
- return NULL;
-}
-
-static void
-request_submit(struct request *const req) {
- if (req->ns) {
- /* if it has a nameserver assigned then this is going */
- /* straight into the inflight queue */
- evdns_request_insert(req, &req_head);
- global_requests_inflight++;
- evdns_request_transmit(req);
- } else {
- evdns_request_insert(req, &req_waiting_head);
- global_requests_waiting++;
- }
-}
-
-/* exported function */
-int evdns_resolve_ipv4(const char *name, int flags,
- evdns_callback_type callback, void *ptr) {
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
- if (flags & DNS_QUERY_NO_SEARCH) {
- struct request *const req =
- request_new(TYPE_A, name, flags, callback, ptr);
- if (req == NULL)
- return (1);
- request_submit(req);
- return (0);
- } else {
- return (search_request_new(TYPE_A, name, flags, callback, ptr));
- }
-}
-
-/* exported function */
-int evdns_resolve_ipv6(const char *name, int flags,
- evdns_callback_type callback, void *ptr) {
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
- if (flags & DNS_QUERY_NO_SEARCH) {
- struct request *const req =
- request_new(TYPE_AAAA, name, flags, callback, ptr);
- if (req == NULL)
- return (1);
- request_submit(req);
- return (0);
- } else {
- return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
- }
-}
-
-int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- char buf[32];
- struct request *req;
- u32 a;
- assert(in);
- a = ntohl(in->s_addr);
- evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
- (int)(u8)((a )&0xff),
- (int)(u8)((a>>8 )&0xff),
- (int)(u8)((a>>16)&0xff),
- (int)(u8)((a>>24)&0xff));
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
- req = request_new(TYPE_PTR, buf, flags, callback, ptr);
- if (!req) return 1;
- request_submit(req);
- return 0;
-}
-
-int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
- char buf[73];
- char *cp;
- struct request *req;
- int i;
- assert(in);
- cp = buf;
- for (i=15; i >= 0; --i) {
- u8 byte = in->s6_addr[i];
- *cp++ = "0123456789abcdef"[byte & 0x0f];
- *cp++ = '.';
- *cp++ = "0123456789abcdef"[byte >> 4];
- *cp++ = '.';
- }
- assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
- memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
- req = request_new(TYPE_PTR, buf, flags, callback, ptr);
- if (!req) return 1;
- request_submit(req);
- return 0;
-}
-
-/*/////////////////////////////////////////////////////////////////// */
-/* Search support */
-/* */
-/* the libc resolver has support for searching a number of domains */
-/* to find a name. If nothing else then it takes the single domain */
-/* from the gethostname() call. */
-/* */
-/* It can also be configured via the domain and search options in a */
-/* resolv.conf. */
-/* */
-/* The ndots option controls how many dots it takes for the resolver */
-/* to decide that a name is non-local and so try a raw lookup first. */
-
-struct search_domain {
- int len;
- struct search_domain *next;
- /* the text string is appended to this structure */
-};
-
-struct search_state {
- int refcount;
- int ndots;
- int num_domains;
- struct search_domain *head;
-};
-
-static struct search_state *global_search_state = NULL;
-
-static void
-search_state_decref(struct search_state *const state) {
- if (!state) return;
- state->refcount--;
- if (!state->refcount) {
- struct search_domain *next, *dom;
- for (dom = state->head; dom; dom = next) {
- next = dom->next;
- free(dom);
- }
- free(state);
- }
-}
-
-static struct search_state *
-search_state_new(void) {
- struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state));
- if (!state) return NULL;
- memset(state, 0, sizeof(struct search_state));
- state->refcount = 1;
- state->ndots = 1;
-
- return state;
-}
-
-static void
-search_postfix_clear(void) {
- search_state_decref(global_search_state);
-
- global_search_state = search_state_new();
-}
-
-/* exported function */
-void
-evdns_search_clear(void) {
- search_postfix_clear();
-}
-
-static void
-search_postfix_add(const char *domain) {
- int domain_len;
- struct search_domain *sdomain;
- while (domain[0] == '.') domain++;
- domain_len = strlen(domain);
-
- if (!global_search_state) global_search_state = search_state_new();
- if (!global_search_state) return;
- global_search_state->num_domains++;
-
- sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len);
- if (!sdomain) return;
- memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
- sdomain->next = global_search_state->head;
- sdomain->len = domain_len;
-
- global_search_state->head = sdomain;
-}
-
-/* reverse the order of members in the postfix list. This is needed because, */
-/* when parsing resolv.conf we push elements in the wrong order */
-static void
-search_reverse(void) {
- struct search_domain *cur, *prev = NULL, *next;
- cur = global_search_state->head;
- while (cur) {
- next = cur->next;
- cur->next = prev;
- prev = cur;
- cur = next;
- }
-
- global_search_state->head = prev;
-}
-
-/* exported function */
-void
-evdns_search_add(const char *domain) {
- search_postfix_add(domain);
-}
-
-/* exported function */
-void
-evdns_search_ndots_set(const int ndots) {
- if (!global_search_state) global_search_state = search_state_new();
- if (!global_search_state) return;
- global_search_state->ndots = ndots;
-}
-
-static void
-search_set_from_hostname(void) {
- char hostname[HOST_NAME_MAX + 1], *domainname;
-
- search_postfix_clear();
- if (gethostname(hostname, sizeof(hostname))) return;
- domainname = strchr(hostname, '.');
- if (!domainname) return;
- search_postfix_add(domainname);
-}
-
-/* warning: returns malloced string */
-static char *
-search_make_new(const struct search_state *const state, int n, const char *const base_name) {
- const int base_len = strlen(base_name);
- const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
- struct search_domain *dom;
-
- for (dom = state->head; dom; dom = dom->next) {
- if (!n--) {
- /* this is the postfix we want */
- /* the actual postfix string is kept at the end of the structure */
- const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
- const int postfix_len = dom->len;
- char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1);
- if (!newname) return NULL;
- memcpy(newname, base_name, base_len);
- if (need_to_append_dot) newname[base_len] = '.';
- memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
- newname[base_len + need_to_append_dot + postfix_len] = 0;
- return newname;
- }
- }
-
- /* we ran off the end of the list and still didn't find the requested string */
- abort();
- return NULL; /* unreachable; stops warnings in some compilers. */
-}
-
-static int
-search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
- assert(type == TYPE_A || type == TYPE_AAAA);
- if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
- global_search_state &&
- global_search_state->num_domains) {
- /* we have some domains to search */
- struct request *req;
- if (string_num_dots(name) >= global_search_state->ndots) {
- req = request_new(type, name, flags, user_callback, user_arg);
- if (!req) return 1;
- req->search_index = -1;
- } else {
- char *const new_name = search_make_new(global_search_state, 0, name);
- if (!new_name) return 1;
- req = request_new(type, new_name, flags, user_callback, user_arg);
- free(new_name);
- if (!req) return 1;
- req->search_index = 0;
- }
- req->search_origname = strdup(name);
- req->search_state = global_search_state;
- req->search_flags = flags;
- global_search_state->refcount++;
- request_submit(req);
- return 0;
- } else {
- struct request *const req = request_new(type, name, flags, user_callback, user_arg);
- if (!req) return 1;
- request_submit(req);
- return 0;
- }
-}
-
-/* this is called when a request has failed to find a name. We need to check */
-/* if it is part of a search and, if so, try the next name in the list */
-/* returns: */
-/* 0 another request has been submitted */
-/* 1 no more requests needed */
-static int
-search_try_next(struct request *const req) {
- if (req->search_state) {
- /* it is part of a search */
- char *new_name;
- struct request *newreq;
- req->search_index++;
- if (req->search_index >= req->search_state->num_domains) {
- /* no more postfixes to try, however we may need to try */
- /* this name without a postfix */
- if (string_num_dots(req->search_origname) < req->search_state->ndots) {
- /* yep, we need to try it raw */
- newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
- log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
- if (newreq) {
- request_submit(newreq);
- return 0;
- }
- }
- return 1;
- }
-
- new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
- if (!new_name) return 1;
- log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
- newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
- free(new_name);
- if (!newreq) return 1;
- newreq->search_origname = req->search_origname;
- req->search_origname = NULL;
- newreq->search_state = req->search_state;
- newreq->search_flags = req->search_flags;
- newreq->search_index = req->search_index;
- newreq->search_state->refcount++;
- request_submit(newreq);
- return 0;
- }
- return 1;
-}
-
-static void
-search_request_finished(struct request *const req) {
- if (req->search_state) {
- search_state_decref(req->search_state);
- req->search_state = NULL;
- }
- if (req->search_origname) {
- free(req->search_origname);
- req->search_origname = NULL;
- }
-}
-
-/*/////////////////////////////////////////////////////////////////// */
-/* Parsing resolv.conf files */
-
-static void
-evdns_resolv_set_defaults(int flags) {
- /* if the file isn't found then we assume a local resolver */
- if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
- if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
-}
-
-#ifndef HAVE_STRTOK_R
-static char *
-strtok_r(char *s, const char *delim, char **state) {
- return strtok(s, delim);
-}
-#endif
-
-/* helper version of atoi which returns -1 on error */
-static int
-strtoint(const char *const str) {
- char *endptr;
- const int r = strtol(str, &endptr, 10);
- if (*endptr) return -1;
- return r;
-}
-
-/* helper version of atoi that returns -1 on error and clips to bounds. */
-static int
-strtoint_clipped(const char *const str, int min, int max)
-{
- int r = strtoint(str);
- if (r == -1)
- return r;
- else if (r<min)
- return min;
- else if (r>max)
- return max;
- else
- return r;
-}
-
-/* exported function */
-int
-evdns_set_option(const char *option, const char *val, int flags)
-{
- if (!strncmp(option, "ndots:", 6)) {
- const int ndots = strtoint(val);
- if (ndots == -1) return -1;
- if (!(flags & DNS_OPTION_SEARCH)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
- if (!global_search_state) global_search_state = search_state_new();
- if (!global_search_state) return -1;
- global_search_state->ndots = ndots;
- } else if (!strncmp(option, "timeout:", 8)) {
- const int timeout = strtoint(val);
- if (timeout == -1) return -1;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
- global_timeout.tv_sec = timeout;
- } else if (!strncmp(option, "max-timeouts:", 12)) {
- const int maxtimeout = strtoint_clipped(val, 1, 255);
- if (maxtimeout == -1) return -1;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
- maxtimeout);
- global_max_nameserver_timeout = maxtimeout;
- } else if (!strncmp(option, "max-inflight:", 13)) {
- const int maxinflight = strtoint_clipped(val, 1, 65000);
- if (maxinflight == -1) return -1;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
- maxinflight);
- global_max_requests_inflight = maxinflight;
- } else if (!strncmp(option, "attempts:", 9)) {
- int retries = strtoint(val);
- if (retries == -1) return -1;
- if (retries > 255) retries = 255;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
- global_max_retransmits = retries;
- }
- return 0;
-}
-
-static void
-resolv_conf_parse_line(char *const start, int flags) {
- char *strtok_state;
- static const char *const delims = " \t";
-#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
-
- char *const first_token = strtok_r(start, delims, &strtok_state);
- if (!first_token) return;
-
- if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
- const char *const nameserver = NEXT_TOKEN;
- struct in_addr ina;
-
- if (inet_aton(nameserver, &ina)) {
- /* address is valid */
- evdns_nameserver_add(ina.s_addr);
- }
- } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
- const char *const domain = NEXT_TOKEN;
- if (domain) {
- search_postfix_clear();
- search_postfix_add(domain);
- }
- } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
- const char *domain;
- search_postfix_clear();
-
- while ((domain = NEXT_TOKEN)) {
- search_postfix_add(domain);
- }
- search_reverse();
- } else if (!strcmp(first_token, "options")) {
- const char *option;
- while ((option = NEXT_TOKEN)) {
- const char *val = strchr(option, ':');
- evdns_set_option(option, val ? val+1 : "", flags);
- }
- }
-#undef NEXT_TOKEN
-}
-
-/* exported function */
-/* returns: */
-/* 0 no errors */
-/* 1 failed to open file */
-/* 2 failed to stat file */
-/* 3 file too large */
-/* 4 out of memory */
-/* 5 short read from file */
-int
-evdns_resolv_conf_parse(int flags, const char *const filename) {
- struct stat st;
- int fd, n, r;
- u8 *resolv;
- char *start;
- int err = 0;
-
- log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
-
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- evdns_resolv_set_defaults(flags);
- return 1;
- }
-
- if (fstat(fd, &st)) { err = 2; goto out1; }
- if (!st.st_size) {
- evdns_resolv_set_defaults(flags);
- err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
- goto out1;
- }
- if (st.st_size > 65535) { err = 3; goto out1; } /* no resolv.conf should be any bigger */
-
- resolv = (u8 *) malloc((size_t)st.st_size + 1);
- if (!resolv) { err = 4; goto out1; }
-
- n = 0;
- while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
- n += r;
- if (n == st.st_size)
- break;
- assert(n < st.st_size);
- }
- if (r < 0) { err = 5; goto out2; }
- resolv[n] = 0; /* we malloced an extra byte; this should be fine. */
-
- start = (char *) resolv;
- for (;;) {
- char *const newline = strchr(start, '\n');
- if (!newline) {
- resolv_conf_parse_line(start, flags);
- break;
- } else {
- *newline = 0;
- resolv_conf_parse_line(start, flags);
- start = newline + 1;
- }
- }
-
- if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
- /* no nameservers were configured. */
- evdns_nameserver_ip_add("127.0.0.1");
- err = 6;
- }
- if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
- search_set_from_hostname();
- }
-
-out2:
- free(resolv);
-out1:
- close(fd);
- return err;
-}
-
-int
-evdns_init(void)
-{
- int res = 0;
-
- res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
-
- return (res);
-}
-
-const char *
-evdns_err_to_string(int err)
-{
- switch (err) {
- case DNS_ERR_NONE: return "no error";
- case DNS_ERR_FORMAT: return "misformatted query";
- case DNS_ERR_SERVERFAILED: return "server failed";
- case DNS_ERR_NOTEXIST: return "name does not exist";
- case DNS_ERR_NOTIMPL: return "query not implemented";
- case DNS_ERR_REFUSED: return "refused";
-
- case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
- case DNS_ERR_UNKNOWN: return "unknown";
- case DNS_ERR_TIMEOUT: return "request timed out";
- case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
- default: return "[Unknown error code]";
- }
-}
-
-void
-evdns_shutdown(int fail_requests)
-{
- struct nameserver *server, *server_next;
- struct search_domain *dom, *dom_next;
-
- while (req_head) {
- if (fail_requests)
- reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL);
- request_finished(req_head, &req_head);
- }
- while (req_waiting_head) {
- if (fail_requests)
- reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
- request_finished(req_waiting_head, &req_waiting_head);
- }
- global_requests_inflight = global_requests_waiting = 0;
-
- for (server = server_head; server; server = server_next) {
- server_next = server->next;
- if (server->socket >= 0)
- CLOSE_SOCKET(server->socket);
- (void) event_del(&server->event);
- if (server->state == 0)
- (void) event_del(&server->timeout_event);
- free(server);
- if (server_next == server_head)
- break;
- }
- server_head = NULL;
- global_good_nameservers = 0;
-
- if (global_search_state) {
- for (dom = global_search_state->head; dom; dom = dom_next) {
- dom_next = dom->next;
- free(dom);
- }
- free(global_search_state);
- global_search_state = NULL;
- }
- evdns_log_fn = NULL;
-}
-
-#ifdef EVDNS_MAIN
-void
-main_callback(int result, char type, int count, int ttl,
- void *addrs, void *orig) {
- char *n = (char*)orig;
- int i;
- for (i = 0; i < count; ++i) {
- if (type == DNS_IPv4_A) {
- printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
- } else if (type == DNS_PTR) {
- printf("%s: %s\n", n, ((char**)addrs)[i]);
- }
- }
- if (!count) {
- printf("%s: No answer (%d)\n", n, result);
- }
- fflush(stdout);
-}
-void
-evdns_server_callback(struct evdns_server_request *req, void *data)
-{
- int i, r;
- (void)data;
- /* dummy; give 192.168.11.11 as an answer for all A questions,
- * give foo.bar.example.com as an answer for all PTR questions. */
- for (i = 0; i < req->nquestions; ++i) {
- u32 ans = htonl(0xc0a80b0bUL);
- if (req->questions[i]->type == EVDNS_TYPE_A &&
- req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
- printf(" -- replying for %s (A)\n", req->questions[i]->name);
- r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
- 1, &ans, 10);
- if (r<0)
- printf("eeep, didn't work.\n");
- } else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
- req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
- printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
- r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
- "foo.bar.example.com", 10);
- } else {
- printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
- req->questions[i]->type, req->questions[i]->dns_question_class);
- }
- }
-
- r = evdns_request_respond(req, 0);
- if (r<0)
- printf("eeek, couldn't send reply.\n");
-}
-
-void
-logfn(int is_warn, const char *msg) {
- (void) is_warn;
- fprintf(stderr, "%s\n", msg);
-}
-int
-main(int c, char **v) {
- int idx;
- int reverse = 0, verbose = 1, servertest = 0;
- if (c<2) {
- fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
- fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
- return 1;
- }
- idx = 1;
- while (idx < c && v[idx][0] == '-') {
- if (!strcmp(v[idx], "-x"))
- reverse = 1;
- else if (!strcmp(v[idx], "-v"))
- verbose = 1;
- else if (!strcmp(v[idx], "-servertest"))
- servertest = 1;
- else
- fprintf(stderr, "Unknown option %s\n", v[idx]);
- ++idx;
- }
- event_init();
- if (verbose)
- evdns_set_log_fn(logfn);
- evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
- if (servertest) {
- int sock;
- struct sockaddr_in my_addr;
- sock = socket(PF_INET, SOCK_DGRAM, 0);
- evutil_make_socket_nonblocking(sock);
- my_addr.sin_family = AF_INET;
- my_addr.sin_port = htons(10053);
- my_addr.sin_addr.s_addr = INADDR_ANY;
- if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
- perror("bind");
- exit(1);
- }
- evdns_add_server_port(sock, 0, evdns_server_callback, NULL);
- }
- for (; idx < c; ++idx) {
- if (reverse) {
- struct in_addr addr;
- if (!inet_aton(v[idx], &addr)) {
- fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
- continue;
- }
- fprintf(stderr, "resolving %s...\n",v[idx]);
- evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
- } else {
- fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
- evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
- }
- }
- fflush(stdout);
- event_dispatch();
- return 0;
-}
-#endif
diff --git a/lib/libevent/evdns.h b/lib/libevent/evdns.h
deleted file mode 100644
index dd71aac650c..00000000000
--- a/lib/libevent/evdns.h
+++ /dev/null
@@ -1,513 +0,0 @@
-/* $NetBSD: evdns.h,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * The original DNS code is due to Adam Langley with heavy
- * modifications by Nick Mathewson. Adam put his DNS software in the
- * public domain. You can find his original copyright below. Please,
- * aware that the code as part of libevent is governed by the 3-clause
- * BSD license above.
- *
- * This software is Public Domain. To view a copy of the public domain dedication,
- * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
- * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
- *
- * I ask and expect, but do not require, that all derivative works contain an
- * attribution similar to:
- * Parts developed by Adam Langley <agl@imperialviolet.org>
- *
- * You may wish to replace the word "Parts" with something else depending on
- * the amount of original code.
- *
- * (Derivative works does not include programs which link against, run or include
- * the source verbatim in their source distributions)
- */
-
-/** @file evdns.h
- *
- * Welcome, gentle reader
- *
- * Async DNS lookups are really a whole lot harder than they should be,
- * mostly stemming from the fact that the libc resolver has never been
- * very good at them. Before you use this library you should see if libc
- * can do the job for you with the modern async call getaddrinfo_a
- * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
- * please continue.
- *
- * This code is based on libevent and you must call event_init before
- * any of the APIs in this file. You must also seed the OpenSSL random
- * source if you are using OpenSSL for ids (see below).
- *
- * This library is designed to be included and shipped with your source
- * code. You statically link with it. You should also test for the
- * existence of strtok_r and define HAVE_STRTOK_R if you have it.
- *
- * The DNS protocol requires a good source of id numbers and these
- * numbers should be unpredictable for spoofing reasons. There are
- * three methods for generating them here and you must define exactly
- * one of them. In increasing order of preference:
- *
- * DNS_USE_GETTIMEOFDAY_FOR_ID:
- * Using the bottom 16 bits of the usec result from gettimeofday. This
- * is a pretty poor solution but should work anywhere.
- * DNS_USE_CPU_CLOCK_FOR_ID:
- * Using the bottom 16 bits of the nsec result from the CPU's time
- * counter. This is better, but may not work everywhere. Requires
- * POSIX realtime support and you'll need to link against -lrt on
- * glibc systems at least.
- * DNS_USE_OPENSSL_FOR_ID:
- * Uses the OpenSSL RAND_bytes call to generate the data. You must
- * have seeded the pool before making any calls to this library.
- *
- * The library keeps track of the state of nameservers and will avoid
- * them when they go down. Otherwise it will round robin between them.
- *
- * Quick start guide:
- * #include "evdns.h"
- * void callback(int result, char type, int count, int ttl,
- * void *addresses, void *arg);
- * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
- * evdns_resolve("www.hostname.com", 0, callback, NULL);
- *
- * When the lookup is complete the callback function is called. The
- * first argument will be one of the DNS_ERR_* defines in evdns.h.
- * Hopefully it will be DNS_ERR_NONE, in which case type will be
- * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
- * which the data can be cached for (in seconds), addresses will point
- * to an array of uint32_t's and arg will be whatever you passed to
- * evdns_resolve.
- *
- * Searching:
- *
- * In order for this library to be a good replacement for glibc's resolver it
- * supports searching. This involves setting a list of default domains, in
- * which names will be queried for. The number of dots in the query name
- * determines the order in which this list is used.
- *
- * Searching appears to be a single lookup from the point of view of the API,
- * although many DNS queries may be generated from a single call to
- * evdns_resolve. Searching can also drastically slow down the resolution
- * of names.
- *
- * To disable searching:
- * 1. Never set it up. If you never call evdns_resolv_conf_parse or
- * evdns_search_add then no searching will occur.
- *
- * 2. If you do call evdns_resolv_conf_parse then don't pass
- * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
- *
- * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
- *
- * The order of searches depends on the number of dots in the name. If the
- * number is greater than the ndots setting then the names is first tried
- * globally. Otherwise each search domain is appended in turn.
- *
- * The ndots setting can either be set from a resolv.conf, or by calling
- * evdns_search_ndots_set.
- *
- * For example, with ndots set to 1 (the default) and a search domain list of
- * ["myhome.net"]:
- * Query: www
- * Order: www.myhome.net, www.
- *
- * Query: www.abc
- * Order: www.abc., www.abc.myhome.net
- *
- * Internals:
- *
- * Requests are kept in two queues. The first is the inflight queue. In
- * this queue requests have an allocated transaction id and nameserver.
- * They will soon be transmitted if they haven't already been.
- *
- * The second is the waiting queue. The size of the inflight ring is
- * limited and all other requests wait in waiting queue for space. This
- * bounds the number of concurrent requests so that we don't flood the
- * nameserver. Several algorithms require a full walk of the inflight
- * queue and so bounding its size keeps thing going nicely under huge
- * (many thousands of requests) loads.
- *
- * If a nameserver loses too many requests it is considered down and we
- * try not to use it. After a while we send a probe to that nameserver
- * (a lookup for google.com) and, if it replies, we consider it working
- * again. If the nameserver fails a probe we wait longer to try again
- * with the next probe.
- */
-
-#ifndef EVENTDNS_H
-#define EVENTDNS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* For integer types. */
-#include <evutil.h>
-
-/** Error codes 0-5 are as described in RFC 1035. */
-#define DNS_ERR_NONE 0
-/** The name server was unable to interpret the query */
-#define DNS_ERR_FORMAT 1
-/** The name server was unable to process this query due to a problem with the
- * name server */
-#define DNS_ERR_SERVERFAILED 2
-/** The domain name does not exist */
-#define DNS_ERR_NOTEXIST 3
-/** The name server does not support the requested kind of query */
-#define DNS_ERR_NOTIMPL 4
-/** The name server refuses to reform the specified operation for policy
- * reasons */
-#define DNS_ERR_REFUSED 5
-/** The reply was truncated or ill-formated */
-#define DNS_ERR_TRUNCATED 65
-/** An unknown error occurred */
-#define DNS_ERR_UNKNOWN 66
-/** Communication with the server timed out */
-#define DNS_ERR_TIMEOUT 67
-/** The request was canceled because the DNS subsystem was shut down. */
-#define DNS_ERR_SHUTDOWN 68
-
-#define DNS_IPv4_A 1
-#define DNS_PTR 2
-#define DNS_IPv6_AAAA 3
-
-#define DNS_QUERY_NO_SEARCH 1
-
-#define DNS_OPTION_SEARCH 1
-#define DNS_OPTION_NAMESERVERS 2
-#define DNS_OPTION_MISC 4
-#define DNS_OPTIONS_ALL 7
-
-/**
- * The callback that contains the results from a lookup.
- * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
- * - count contains the number of addresses of form type
- * - ttl is the number of seconds the resolution may be cached for.
- * - addresses needs to be cast according to type
- */
-typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
-
-/**
- Initialize the asynchronous DNS library.
-
- This function initializes support for non-blocking name resolution by
- calling evdns_resolv_conf_parse().
-
- @return 0 if successful, or -1 if an error occurred
- @see evdns_shutdown()
- */
-int evdns_init(void);
-
-
-/**
- Shut down the asynchronous DNS resolver and terminate all active requests.
-
- If the 'fail_requests' option is enabled, all active requests will return
- an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
- the requests will be silently discarded.
-
- @param fail_requests if zero, active requests will be aborted; if non-zero,
- active requests will return DNS_ERR_SHUTDOWN.
- @see evdns_init()
- */
-void evdns_shutdown(int fail_requests);
-
-
-/**
- Convert a DNS error code to a string.
-
- @param err the DNS error code
- @return a string containing an explanation of the error code
-*/
-const char *evdns_err_to_string(int err);
-
-
-/**
- Add a nameserver.
-
- The address should be an IPv4 address in network byte order.
- The type of address is chosen so that it matches in_addr.s_addr.
-
- @param address an IP address in network byte order
- @return 0 if successful, or -1 if an error occurred
- @see evdns_nameserver_ip_add()
- */
-int evdns_nameserver_add(unsigned long int address);
-
-
-/**
- Get the number of configured nameservers.
-
- This returns the number of configured nameservers (not necessarily the
- number of running nameservers). This is useful for double-checking
- whether our calls to the various nameserver configuration functions
- have been successful.
-
- @return the number of configured nameservers
- @see evdns_nameserver_add()
- */
-int evdns_count_nameservers(void);
-
-
-/**
- Remove all configured nameservers, and suspend all pending resolves.
-
- Resolves will not necessarily be re-attempted until evdns_resume() is called.
-
- @return 0 if successful, or -1 if an error occurred
- @see evdns_resume()
- */
-int evdns_clear_nameservers_and_suspend(void);
-
-
-/**
- Resume normal operation and continue any suspended resolve requests.
-
- Re-attempt resolves left in limbo after an earlier call to
- evdns_clear_nameservers_and_suspend().
-
- @return 0 if successful, or -1 if an error occurred
- @see evdns_clear_nameservers_and_suspend()
- */
-int evdns_resume(void);
-
-
-/**
- Add a nameserver.
-
- This wraps the evdns_nameserver_add() function by parsing a string as an IP
- address and adds it as a nameserver.
-
- @return 0 if successful, or -1 if an error occurred
- @see evdns_nameserver_add()
- */
-int evdns_nameserver_ip_add(const char *ip_as_string);
-
-
-/**
- Lookup an A record for a given name.
-
- @param name a DNS hostname
- @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
- @param callback a callback function to invoke when the request is completed
- @param ptr an argument to pass to the callback function
- @return 0 if successful, or -1 if an error occurred
- @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
- */
-int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
-
-
-/**
- Lookup an AAAA record for a given name.
-
- @param name a DNS hostname
- @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
- @param callback a callback function to invoke when the request is completed
- @param ptr an argument to pass to the callback function
- @return 0 if successful, or -1 if an error occurred
- @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
- */
-int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
-
-struct in_addr;
-struct in6_addr;
-
-/**
- Lookup a PTR record for a given IP address.
-
- @param in an IPv4 address
- @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
- @param callback a callback function to invoke when the request is completed
- @param ptr an argument to pass to the callback function
- @return 0 if successful, or -1 if an error occurred
- @see evdns_resolve_reverse_ipv6()
- */
-int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
-
-
-/**
- Lookup a PTR record for a given IPv6 address.
-
- @param in an IPv6 address
- @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
- @param callback a callback function to invoke when the request is completed
- @param ptr an argument to pass to the callback function
- @return 0 if successful, or -1 if an error occurred
- @see evdns_resolve_reverse_ipv6()
- */
-int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
-
-
-/**
- Set the value of a configuration option.
-
- The currently available configuration options are:
-
- ndots, timeout, max-timeouts, max-inflight, and attempts
-
- @param option the name of the configuration option to be modified
- @param val the value to be set
- @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC
- @return 0 if successful, or -1 if an error occurred
- */
-int evdns_set_option(const char *option, const char *val, int flags);
-
-
-/**
- Parse a resolv.conf file.
-
- The 'flags' parameter determines what information is parsed from the
- resolv.conf file. See the man page for resolv.conf for the format of this
- file.
-
- The following directives are not parsed from the file: sortlist, rotate,
- no-check-names, inet6, debug.
-
- If this function encounters an error, the possible return values are: 1 =
- failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
- memory, 5 = short read from file, 6 = no nameservers listed in the file
-
- @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
- DNS_OPTIONS_ALL
- @param filename the path to the resolv.conf file
- @return 0 if successful, or various positive error codes if an error
- occurred (see above)
- @see resolv.conf(3)
- */
-int evdns_resolv_conf_parse(int flags, const char *const filename);
-
-
-/**
- Clear the list of search domains.
- */
-void evdns_search_clear(void);
-
-
-/**
- Add a domain to the list of search domains
-
- @param domain the domain to be added to the search list
- */
-void evdns_search_add(const char *domain);
-
-
-/**
- Set the 'ndots' parameter for searches.
-
- Sets the number of dots which, when found in a name, causes
- the first query to be without any search domain.
-
- @param ndots the new ndots parameter
- */
-void evdns_search_ndots_set(const int ndots);
-
-/**
- A callback that is invoked when a log message is generated
-
- @param is_warning indicates if the log message is a 'warning'
- @param msg the content of the log message
- */
-typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
-
-
-/**
- Set the callback function to handle log messages.
-
- @param fn the callback to be invoked when a log message is generated
- */
-void evdns_set_log_fn(evdns_debug_log_fn_type fn);
-
-/**
- Set a callback that will be invoked to generate transaction IDs. By
- default, we pick transaction IDs based on the current clock time.
-
- @param fn the new callback, or NULL to use the default.
- */
-void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
-
-#define DNS_NO_SEARCH 1
-
-/*
- * Structures and functions used to implement a DNS server.
- */
-
-struct evdns_server_request {
- int flags;
- int nquestions;
- struct evdns_server_question **questions;
-};
-struct evdns_server_question {
- int type;
-#ifdef __cplusplus
- int dns_question_class;
-#else
- /* You should refer to this field as "dns_question_class". The
- * name "class" works in C for backward compatibility, and will be
- * removed in a future version. (1.5 or later). */
- int class;
-#define dns_question_class class
-#endif
- char name[1];
-};
-typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
-#define EVDNS_ANSWER_SECTION 0
-#define EVDNS_AUTHORITY_SECTION 1
-#define EVDNS_ADDITIONAL_SECTION 2
-
-#define EVDNS_TYPE_A 1
-#define EVDNS_TYPE_NS 2
-#define EVDNS_TYPE_CNAME 5
-#define EVDNS_TYPE_SOA 6
-#define EVDNS_TYPE_PTR 12
-#define EVDNS_TYPE_MX 15
-#define EVDNS_TYPE_TXT 16
-#define EVDNS_TYPE_AAAA 28
-
-#define EVDNS_QTYPE_AXFR 252
-#define EVDNS_QTYPE_ALL 255
-
-#define EVDNS_CLASS_INET 1
-
-struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
-void evdns_close_server_port(struct evdns_server_port *port);
-
-int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
-int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
-int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
-int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
-int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
-
-int evdns_server_request_respond(struct evdns_server_request *req, int err);
-int evdns_server_request_drop(struct evdns_server_request *req);
-struct sockaddr;
-int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !EVENTDNS_H */
diff --git a/lib/libevent/event-internal.h b/lib/libevent/event-internal.h
deleted file mode 100644
index fe91bfd681a..00000000000
--- a/lib/libevent/event-internal.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* $NetBSD: event-internal.h,v 1.2 2008/05/16 20:24:57 peter Exp $ */
-/*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVENT_INTERNAL_H_
-#define _EVENT_INTERNAL_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "config.h"
-#include "min_heap.h"
-#include "evsignal.h"
-
-struct eventop {
- const char *name;
- void *(*init)(struct event_base *);
- int (*add)(void *, struct event *);
- int (*del)(void *, struct event *);
- int (*dispatch)(struct event_base *, void *, struct timeval *);
- void (*dealloc)(struct event_base *, void *);
- /* set if we need to reinitialize the event base */
- int need_reinit;
-};
-
-struct event_base {
- const struct eventop *evsel;
- void *evbase;
- int event_count; /* counts number of total events */
- int event_count_active; /* counts number of active events */
-
- int event_gotterm; /* Set to terminate loop */
- int event_break; /* Set to terminate loop immediately */
-
- /* active event management */
- struct event_list **activequeues;
- int nactivequeues;
-
- /* signal handling info */
- struct evsignal_info sig;
-
- struct event_list eventqueue;
- struct timeval event_tv;
-
- struct min_heap timeheap;
-
- struct timeval tv_cache;
-};
-
-/* Internal use only: Functions that might be missing from <sys/queue.h> */
-#ifndef HAVE_TAILQFOREACH
-#define TAILQ_FIRST(head) ((head)->tqh_first)
-#define TAILQ_END(head) NULL
-#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-#define TAILQ_FOREACH(var, head, field) \
- for((var) = TAILQ_FIRST(head); \
- (var) != TAILQ_END(head); \
- (var) = TAILQ_NEXT(var, field))
-#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
- (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
- (elm)->field.tqe_next = (listelm); \
- *(listelm)->field.tqe_prev = (elm); \
- (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
-} while (0)
-#endif /* TAILQ_FOREACH */
-
-int _evsignal_set_handler(struct event_base *base, int evsignal,
- void (*fn)(int));
-int _evsignal_restore_handler(struct event_base *base, int evsignal);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _EVENT_INTERNAL_H_ */
diff --git a/lib/libevent/event.3 b/lib/libevent/event.3
deleted file mode 100644
index 2fd85dd86bc..00000000000
--- a/lib/libevent/event.3
+++ /dev/null
@@ -1,623 +0,0 @@
-.\" $NetBSD: event.3,v 1.11 2008/05/16 20:24:57 peter Exp $
-.\" $OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $
-.\"
-.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.Dd May 14, 2008
-.Dt EVENT 3
-.Os
-.Sh NAME
-.Nm event_init ,
-.Nm event_dispatch ,
-.Nm event_loop ,
-.Nm event_loopexit ,
-.Nm event_loopbreak ,
-.Nm event_set ,
-.Nm event_base_dispatch ,
-.Nm event_base_loop ,
-.Nm event_base_loopexit ,
-.Nm event_base_loopbreak ,
-.Nm event_base_set ,
-.Nm event_base_free ,
-.Nm event_add ,
-.Nm event_del ,
-.Nm event_once ,
-.Nm event_base_once ,
-.Nm event_pending ,
-.Nm event_initialized ,
-.Nm event_priority_init ,
-.Nm event_priority_set ,
-.Nm evtimer_set ,
-.Nm evtimer_add ,
-.Nm evtimer_del ,
-.Nm evtimer_pending ,
-.Nm evtimer_initialized ,
-.Nm signal_set ,
-.Nm signal_add ,
-.Nm signal_del ,
-.Nm signal_pending ,
-.Nm signal_initialized ,
-.Nm bufferevent_new ,
-.Nm bufferevent_free ,
-.Nm bufferevent_write ,
-.Nm bufferevent_write_buffer ,
-.Nm bufferevent_read ,
-.Nm bufferevent_enable ,
-.Nm bufferevent_disable ,
-.Nm bufferevent_settimeout ,
-.Nm bufferevent_base_set ,
-.Nm evbuffer_new ,
-.Nm evbuffer_free ,
-.Nm evbuffer_add ,
-.Nm evbuffer_add_buffer ,
-.Nm evbuffer_add_printf ,
-.Nm evbuffer_add_vprintf ,
-.Nm evbuffer_drain ,
-.Nm evbuffer_write ,
-.Nm evbuffer_read ,
-.Nm evbuffer_find ,
-.Nm evbuffer_readline ,
-.Nm evhttp_new ,
-.Nm evhttp_bind_socket ,
-.Nm evhttp_free
-.Nd execute a function when a specific event occurs
-.Sh LIBRARY
-.Lb libevent
-.Sh SYNOPSIS
-.In sys/time.h
-.In event.h
-.Ft "struct event_base *"
-.Fn event_init
-.Ft int
-.Fn event_dispatch
-.Ft int
-.Fn event_loop "int flags"
-.Ft int
-.Fn event_loopexit "struct timeval *tv"
-.Ft int
-.Fn event_loopbreak void
-.Ft int
-.Fn event_base_dispatch "struct event_base *base"
-.Ft void
-.Fn event_base_free "struct event_base *base"
-.Ft int
-.Fn event_base_loop "struct event_base *base" "int flags"
-.Ft int
-.Fn event_base_loopexit "struct event_base *base" "struct timeval *tv"
-.Ft int
-.Fn event_base_loopbreak "struct event_base *base"
-.Ft int
-.Fn event_base_set "struct event_base *base" "struct event *"
-.Ft void
-.Fn event_set "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
-.Ft int
-.Fn event_add "struct event *ev" "struct timeval *tv"
-.Ft int
-.Fn event_del "struct event *ev"
-.Ft int
-.Fn event_once "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
-.Ft inr
-.Fn event_base_once "struct event_base *base" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
-.Ft int
-.Fn event_pending "struct event *ev" "short event" "struct timeval *tv"
-.Ft int
-.Fn event_initialized "struct event *ev"
-.Ft void
-.Fn evtimer_set "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
-.Ft void
-.Fn evtimer_add "struct event *ev" "struct timeval *tv"
-.Ft void
-.Fn evtimer_del "struct event *ev"
-.Ft int
-.Fn evtimer_pending "struct event *ev" "struct timeval *tv"
-.Ft int
-.Fn evtimer_initialized "struct event *ev"
-.Ft void
-.Fn signal_set "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg"
-.Ft void
-.Fn signal_add "struct event *ev" "struct timeval *tv"
-.Ft void
-.Fn signal_del "struct event *ev"
-.Ft int
-.Fn signal_pending "struct event *ev" "struct timeval *tv"
-.Ft int
-.Fn signal_initialized "struct event *ev"
-.Ft "struct bufferevent *"
-.Fn bufferevent_new "int fd" "evbuffercb readcb" "evbuffercb writecb" "everrorcb" "void *cbarg"
-.Ft void
-.Fn bufferevent_free "struct bufferevent *bufev"
-.Ft int
-.Fn bufferevent_write "struct bufferevent *bufev" "void *data" "size_t size"
-.Ft int
-.Fn bufferevent_write_buffer "struct bufferevent *bufev" "struct evbuffer *buf"
-.Ft size_t
-.Fn bufferevent_read "struct bufferevent *bufev" "void *data" "size_t size"
-.Ft int
-.Fn bufferevent_enable "struct bufferevent *bufev" "short event"
-.Ft int
-.Fn bufferevent_disable "struct bufferevent *bufev" "short event"
-.Ft void
-.Fn bufferevent_settimeout "struct bufferevent *bufev" "int timeout_read" "int timeout_write"
-.Ft int
-.Fn bufferevent_base_set "struct event_base *base" "struct bufferevent *bufev"
-.Ft "struct evbuffer *"
-.Fn evbuffer_new "void"
-.Ft void
-.Fn evbuffer_free "struct evbuffer *buf"
-.Ft int
-.Fn evbuffer_add "struct evbuffer *buf" "const void *data" "size_t size"
-.Ft int
-.Fn evbuffer_add_buffer "struct evbuffer *dst" "struct evbuffer *src"
-.Ft int
-.Fn evbuffer_add_printf "struct evbuffer *buf" "const char *fmt" "..."
-.Ft int
-.Fn evbuffer_add_vprintf "struct evbuffer *buf" "const char *fmt" "va_list ap"
-.Ft void
-.Fn evbuffer_drain "struct evbuffer *buf" "size_t size"
-.Ft int
-.Fn evbuffer_write "struct evbuffer *buf" "int fd"
-.Ft int
-.Fn evbuffer_read "struct evbuffer *buf" "int fd" "int size"
-.Ft "u_char *"
-.Fn evbuffer_find "struct evbuffer *buf" "const u_char *data" "size_t size"
-.Ft "char *"
-.Fn evbuffer_readline "struct evbuffer *buf"
-.Ft "struct evhttp *"
-.Fn evhttp_new "struct event_base *base"
-.Ft int
-.Fn evhttp_bind_socket "struct evhttp *http" "const char *address" "u_short port"
-.Ft void
-.Fn evhttp_free "struct evhttp *http"
-.Ft int
-.Fa (*event_sigcb)(void) ;
-.Ft volatile sig_atomic_t
-.Fa event_gotsig ;
-.Sh DESCRIPTION
-The
-.Nm event
-API provides a mechanism to execute a function when a specific event
-on a file descriptor occurs or after a given time has passed.
-.Pp
-The
-.Nm event
-API needs to be initialized with
-.Fn event_init
-before it can be used.
-.Pp
-In order to process events, an application needs to call
-.Fn event_dispatch .
-This function only returns on error, and should replace the event core
-of the application program.
-.Pp
-The function
-.Fn event_set
-prepares the event structure
-.Fa ev
-to be used in future calls to
-.Fn event_add
-and
-.Fn event_del .
-The event will be prepared to call the function specified by the
-.Fa fn
-argument with an
-.Fa int
-argument indicating the file descriptor, a
-.Fa short
-argument indicating the type of event, and a
-.Fa void *
-argument given in the
-.Fa arg
-argument.
-The
-.Fa fd
-indicates the file descriptor that should be monitored for events.
-The events can be either
-.Va EV_READ ,
-.Va EV_WRITE ,
-or both,
-indicating that an application can read or write from the file descriptor
-respectively without blocking.
-.Pp
-The function
-.Fa fn
-will be called with the file descriptor that triggered the event and
-the type of event which will be either
-.Va EV_TIMEOUT ,
-.Va EV_SIGNAL ,
-.Va EV_READ ,
-or
-.Va EV_WRITE .
-Additionally, an event which has registered interest in more than one of the
-preceeding events, via bitwise-OR to
-.Fn event_set ,
-can provide its callback function with a bitwise-OR of more than one triggered
-event.
-The additional flag
-.Va EV_PERSIST
-makes an
-.Fn event_add
-persistent until
-.Fn event_del
-has been called.
-.Pp
-Once initialized, the
-.Fa ev
-structure can be used repeatedly with
-.Fn event_add
-and
-.Fn event_del
-and does not need to be reinitialized unless the function called and/or
-the argument to it are to be changed.
-However, when an
-.Fa ev
-structure has been added to libevent using
-.Fn event_add
-the structure must persist until the event occurs (assuming
-.Fa EV_PERSIST
-is not set) or is removed
-using
-.Fn event_del .
-You may not reuse the same
-.Fa ev
-structure for multiple monitored descriptors; each descriptor
-needs its own
-.Fa ev .
-.Pp
-The function
-.Fn event_add
-schedules the execution of the
-.Fa ev
-event when the event specified in
-.Fn event_set
-occurs or in at least the time specified in the
-.Fa tv .
-If
-.Fa tv
-is
-.Dv NULL ,
-no timeout occurs and the function will only be called
-if a matching event occurs on the file descriptor.
-The event in the
-.Fa ev
-argument must be already initialized by
-.Fn event_set
-and may not be used in calls to
-.Fn event_set
-until it has timed out or been removed with
-.Fn event_del .
-If the event in the
-.Fa ev
-argument already has a scheduled timeout, the old timeout will be
-replaced by the new one.
-.Pp
-The function
-.Fn event_del
-will cancel the event in the argument
-.Fa ev .
-If the event has already executed or has never been added
-the call will have no effect.
-.Pp
-The functions
-.Fn evtimer_set ,
-.Fn evtimer_add ,
-.Fn evtimer_del ,
-.Fn evtimer_initialized ,
-and
-.Fn evtimer_pending
-are abbreviations for common situations where only a timeout is required.
-The file descriptor passed will be \-1, and the event type will be
-.Va EV_TIMEOUT .
-.Pp
-The functions
-.Fn signal_set ,
-.Fn signal_add ,
-.Fn signal_del ,
-.Fn signal_initialized ,
-and
-.Fn signal_pending
-are abbreviations.
-The event type will be a persistent
-.Va EV_SIGNAL .
-That means
-.Fn signal_set
-adds
-.Va EV_PERSIST .
-.Pp
-In order to avoid races in signal handlers, the
-.Nm event
-API provides two variables:
-.Va event_sigcb
-and
-.Va event_gotsig .
-A signal handler
-sets
-.Va event_gotsig
-to indicate that a signal has been received.
-The application sets
-.Va event_sigcb
-to a callback function.
-After the signal handler sets
-.Va event_gotsig ,
-.Nm event_dispatch
-will execute the callback function to process received signals.
-The callback returns 1 when no events are registered any more.
-It can return \-1 to indicate an error to the
-.Nm event
-library, causing
-.Fn event_dispatch
-to terminate with
-.Va errno
-set to
-.Er EINTR .
-.Pp
-The function
-.Fn event_once
-is similar to
-.Fn event_set .
-However, it schedules a callback to be called exactly once and does not
-require the caller to prepare an
-.Fa event
-structure.
-This function supports
-.Fa EV_TIMEOUT ,
-.Fa EV_READ ,
-and
-.Fa EV_WRITE .
-.Pp
-The
-.Fn event_pending
-function can be used to check if the event specified by
-.Fa event
-is pending to run.
-If
-.Va EV_TIMEOUT
-was specified and
-.Fa tv
-is not
-.Dv NULL ,
-the expiration time of the event will be returned in
-.Fa tv .
-.Pp
-The
-.Fn event_initialized
-macro can be used to check if an event has been initialized.
-.Pp
-The
-.Nm event_loop
-function provides an interface for single pass execution of pending
-events.
-The flags
-.Va EVLOOP_ONCE
-and
-.Va EVLOOP_NONBLOCK
-are recognized.
-The
-.Nm event_loopexit
-function exits from the event loop. The next
-.Fn event_loop
-iteration after the
-given timer expires will complete normally (handling all queued events) then
-exit without blocking for events again. Subsequent invocations of
-.Fn event_loop
-will proceed normally.
-The
-.Nm event_loopbreak
-function exits from the event loop immediately.
-.Fn event_loop
-will abort after the next event is completed;
-.Fn event_loopbreak
-is typically invoked from this event's callback. This behavior is analogous
-to the "break;" statement. Subsequent invocations of
-.Fn event_loop
-will proceed normally.
-.Pp
-It is the responsibility of the caller to provide these functions with
-pre-allocated event structures.
-.Sh EVENT PRIORITIES
-By default
-.Nm libevent
-schedules all active events with the same priority.
-However, sometimes it is desirable to process some events with a higher
-priority than others.
-For that reason,
-.Nm libevent
-supports strict priority queues.
-Active events with a lower priority are always processed before events
-with a higher priority.
-.Pp
-The number of different priorities can be set initially with the
-.Fn event_priority_init
-function.
-This function should be called before the first call to
-.Fn event_dispatch .
-The
-.Fn event_priority_set
-function can be used to assign a priority to an event.
-By default,
-.Nm libevent
-assigns the middle priority to all events unless their priority
-is explicitly set.
-.Sh THREAD SAFE EVENTS
-.Nm Libevent
-has experimental support for thread-safe events.
-When initializing the library via
-.Fn event_init ,
-an event base is returned.
-This event base can be used in conjunction with calls to
-.Fn event_base_set ,
-.Fn event_base_dispatch ,
-.Fn event_base_loop ,
-.Fn event_base_loopexit ,
-.Fn bufferevent_base_set
-and
-.Fn event_base_free .
-.Fn event_base_set
-should be called after preparing an event with
-.Fn event_set ,
-as
-.Fn event_set
-assigns the provided event to the most recently created event base.
-.Fn bufferevent_base_set
-should be called after preparing a bufferevent with
-.Fn bufferevent_new .
-.Fn event_base_free
-should be used to free memory associated with the event base
-when it is no longer needed.
-.Sh BUFFERED EVENTS
-.Nm libevent
-provides an abstraction on top of the regular event callbacks.
-This abstraction is called a
-.Dq Sy buffered event .
-A buffered event provides input and output buffers that get filled
-and drained automatically.
-The user of a buffered event no longer deals directly with the IO,
-but instead is reading from input and writing to output buffers.
-.Pp
-A new bufferevent is created by
-.Fn bufferevent_new .
-The parameter
-.Fa fd
-specifies the file descriptor from which data is read and written to.
-This file descriptor is not allowed to be a
-.Xr pipe 2 .
-The next three parameters are callbacks.
-The read and write callback have the following form:
-.Ft void
-.Fn "(*cb)" "struct bufferevent *bufev" "void *arg" .
-The error callback has the following form:
-.Ft void
-.Fn "(*cb)" "struct bufferevent *bufev" "short what" "void *arg" .
-The argument is specified by the fourth parameter
-.Fa "cbarg" .
-A
-.Fa bufferevent struct
-pointer is returned on success, NULL on error.
-Both the read and the write callback may be NULL.
-The error callback has to be always provided.
-.Pp
-Once initialized, the bufferevent structure can be used repeatedly with
-.Fn bufferevent_enable
-and
-.Fn bufferevent_disable .
-The flags parameter can be a combination of
-.Va EV_READ
-and
-.Va EV_WRITE .
-When read enabled the bufferevent will try to read from the file
-descriptor and call the read callback.
-The write callback is executed
-whenever the output buffer is drained below the write low watermark,
-which is
-.Va 0
-by default.
-.Pp
-The
-.Fn bufferevent_write
-function can be used to write data to the file descriptor.
-The data is appended to the output buffer and written to the descriptor
-automatically as it becomes available for writing.
-.Fn bufferevent_write
-returns 0 on success or \-1 on failure.
-The
-.Fn bufferevent_read
-function is used to read data from the input buffer,
-returning the amount of data read.
-.Pp
-If multiple bases are in use,
-.Fn bufferevent_base_set
-must be called before enabling the bufferevent for the first time.
-.Sh NON-BLOCKING HTTP SUPPORT
-.Nm libevent
-provides a very thin HTTP layer that can be used both to host an HTTP
-server and also to make HTTP requests.
-An HTTP server can be created by calling
-.Fn evhttp_new .
-It can be bound to any port and address with the
-.Fn evhttp_bind_socket
-function.
-When the HTTP server is no longer used, it can be freed via
-.Fn evhttp_free .
-.Pp
-To be notified of HTTP requests, a user needs to register callbacks with the
-HTTP server.
-This can be done by calling
-.Fn evhttp_set_cb .
-The second argument is the URI for which a callback is being registered.
-The corresponding callback will receive an
-.Va struct evhttp_request
-object that contains all information about the request.
-.Pp
-This section does not document all the possible function calls; please
-check
-.Va event.h
-for the public interfaces.
-.Sh ADDITIONAL NOTES
-It is possible to disable support for
-.Va epoll , kqueue , devpoll , poll
-or
-.Va select
-by setting the environment variable
-.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
-or
-.Va EVENT_NOSELECT ,
-respectively.
-By setting the environment variable
-.Va EVENT_SHOW_METHOD ,
-.Nm libevent
-displays the kernel notification method that it uses.
-.Sh RETURN VALUES
-Upon successful completion
-.Fn event_add
-and
-.Fn event_del
-return 0.
-Otherwise, \-1 is returned and the global variable errno is
-set to indicate the error.
-.Sh SEE ALSO
-.Xr kqueue 2 ,
-.Xr poll 2 ,
-.Xr evdns 3 ,
-.Xr timeout 9
-.Sh HISTORY
-.Nm
-appeared in
-.Nx 2.0 .
-The
-.Nm event
-API manpage is based on the
-.Xr timeout 9
-manpage by Artur Grabowski.
-.Sh AUTHORS
-The
-.Nm event
-library was written by Niels Provos.
-.Sh BUGS
-This documentation is neither complete nor authoritative.
-If you are in doubt about the usage of this API then
-check the source code to find out how it works, write
-up the missing piece of documentation and send it to
-me for inclusion in this man page.
diff --git a/lib/libevent/event.c b/lib/libevent/event.c
deleted file mode 100644
index 7480ce106fb..00000000000
--- a/lib/libevent/event.c
+++ /dev/null
@@ -1,1001 +0,0 @@
-/* $NetBSD: event.c,v 1.10 2009/07/08 21:23:53 tls Exp $ */
-/* $OpenBSD: event.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
-
-/*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#else
-#include <sys/_time.h>
-#endif
-#include <sys/queue.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <assert.h>
-#include <time.h>
-
-#include "event.h"
-#include "event-internal.h"
-#include "evutil.h"
-#include "log.h"
-
-#ifdef HAVE_EVENT_PORTS
-extern const struct eventop evportops;
-#endif
-#ifdef HAVE_SELECT
-extern const struct eventop selectops;
-#endif
-#ifdef HAVE_POLL
-extern const struct eventop pollops;
-#endif
-#ifdef HAVE_WORKING_KQUEUE
-extern const struct eventop kqops;
-#endif
-
-/* In order of preference */
-static const struct eventop *eventops[] = {
-#ifdef HAVE_EVENT_PORTS
- &evportops,
-#endif
-#ifdef HAVE_WORKING_KQUEUE
- &kqops,
-#endif
-#ifdef HAVE_POLL
- &pollops,
-#endif
-#ifdef HAVE_SELECT
- &selectops,
-#endif
- NULL
-};
-
-/* Global state */
-struct event_base *current_base = NULL;
-extern struct event_base *evsignal_base;
-static int use_monotonic;
-
-/* Handle signals - This is a deprecated interface */
-int (*event_sigcb)(void); /* Signal callback when gotsig is set */
-volatile sig_atomic_t event_gotsig; /* Set in signal handler */
-
-/* Prototypes */
-static void event_queue_insert(struct event_base *, struct event *, int);
-static void event_queue_remove(struct event_base *, struct event *, int);
-static int event_haveevents(struct event_base *);
-
-static void event_process_active(struct event_base *);
-
-static int timeout_next(struct event_base *, struct timeval **);
-static void timeout_process(struct event_base *);
-static void timeout_correct(struct event_base *, struct timeval *);
-
-static void
-detect_monotonic(void)
-{
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
- struct timespec ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
- use_monotonic = 1;
-#endif
-}
-
-static int
-gettime(struct event_base *base, struct timeval *tp)
-{
- if (base->tv_cache.tv_sec) {
- *tp = base->tv_cache;
- return (0);
- }
-
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
- if (use_monotonic) {
- struct timespec ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
- return (-1);
-
- tp->tv_sec = ts.tv_sec;
- tp->tv_usec = ts.tv_nsec / 1000;
- return (0);
- }
-#endif
-
- return (evutil_gettimeofday(tp, NULL));
-}
-
-struct event_base *
-event_init(void)
-{
- struct event_base *base = event_base_new();
-
- if (base != NULL)
- current_base = base;
-
- return (base);
-}
-
-struct event_base *
-event_base_new(void)
-{
- int i;
- struct event_base *base;
-
- if ((base = calloc(1, sizeof(struct event_base))) == NULL)
- event_err(1, "%s: calloc", __func__);
-
- event_sigcb = NULL;
- event_gotsig = 0;
-
- detect_monotonic();
- gettime(base, &base->event_tv);
-
- min_heap_ctor(&base->timeheap);
- TAILQ_INIT(&base->eventqueue);
- base->sig.ev_signal_pair[0] = -1;
- base->sig.ev_signal_pair[1] = -1;
-
- base->evbase = NULL;
- for (i = 0; eventops[i] && !base->evbase; i++) {
- base->evsel = eventops[i];
-
- base->evbase = base->evsel->init(base);
- }
-
- if (base->evbase == NULL)
- event_errx(1, "%s: no event mechanism available", __func__);
-
- if (getenv("EVENT_SHOW_METHOD"))
- event_msgx("libevent using: %s\n",
- base->evsel->name);
-
- /* allocate a single active event queue */
- event_base_priority_init(base, 1);
-
- return (base);
-}
-
-void
-event_base_free(struct event_base *base)
-{
- int i, n_deleted=0;
- struct event *ev;
-
- if (base == NULL && current_base)
- base = current_base;
- if (base == current_base)
- current_base = NULL;
-
- /* XXX(niels) - check for internal events first */
- assert(base);
- /* Delete all non-internal events. */
- for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
- struct event *next = TAILQ_NEXT(ev, ev_next);
- if (!(ev->ev_flags & EVLIST_INTERNAL)) {
- event_del(ev);
- ++n_deleted;
- }
- ev = next;
- }
- while ((ev = min_heap_top(&base->timeheap)) != NULL) {
- event_del(ev);
- ++n_deleted;
- }
-
- for (i = 0; i < base->nactivequeues; ++i) {
- for (ev = TAILQ_FIRST(base->activequeues[i]); ev; ) {
- struct event *next = TAILQ_NEXT(ev, ev_active_next);
- if (!(ev->ev_flags & EVLIST_INTERNAL)) {
- event_del(ev);
- ++n_deleted;
- }
- ev = next;
- }
- }
-
- if (n_deleted)
- event_debug(("%s: %d events were still set in base",
- __func__, n_deleted));
-
- if (base->evsel->dealloc != NULL)
- base->evsel->dealloc(base, base->evbase);
-
- for (i = 0; i < base->nactivequeues; ++i)
- assert(TAILQ_EMPTY(base->activequeues[i]));
-
- assert(min_heap_empty(&base->timeheap));
- min_heap_dtor(&base->timeheap);
-
- for (i = 0; i < base->nactivequeues; ++i)
- free(base->activequeues[i]);
- free(base->activequeues);
-
- assert(TAILQ_EMPTY(&base->eventqueue));
-
- free(base);
-}
-
-/* reinitialized the event base after a fork */
-int
-event_reinit(struct event_base *base)
-{
- const struct eventop *evsel = base->evsel;
- void *evbase = base->evbase;
- int res = 0;
- struct event *ev;
-
- /* check if this event mechanism requires reinit */
- if (!evsel->need_reinit)
- return (0);
-
- if (base->sig.ev_signal_added) {
- /* we cannot call event_del here because the base has
- * not been reinitialized yet. */
- event_queue_remove(base, &base->sig.ev_signal,
- EVLIST_INSERTED);
- if (base->sig.ev_signal.ev_flags & EVLIST_ACTIVE)
- event_queue_remove(base, &base->sig.ev_signal,
- EVLIST_ACTIVE);
- base->sig.ev_signal_added = 0;
- }
-
- if (base->evsel->dealloc != NULL)
- base->evsel->dealloc(base, base->evbase);
- evbase = base->evbase = evsel->init(base);
- if (base->evbase == NULL)
- event_errx(1, "%s: could not reinitialize event mechanism",
- __func__);
-
- TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
- if (evsel->add(evbase, ev) == -1)
- res = -1;
- }
-
- return (res);
-}
-
-int
-event_priority_init(int npriorities)
-{
- return event_base_priority_init(current_base, npriorities);
-}
-
-int
-event_base_priority_init(struct event_base *base, int npriorities)
-{
- int i;
-
- if (base->event_count_active)
- return (-1);
-
- if (base->nactivequeues && npriorities != base->nactivequeues) {
- for (i = 0; i < base->nactivequeues; ++i) {
- free(base->activequeues[i]);
- }
- free(base->activequeues);
- }
-
- /* Allocate our priority queues */
- base->nactivequeues = npriorities;
- base->activequeues = (struct event_list **)calloc(base->nactivequeues,
- npriorities * sizeof(struct event_list *));
- if (base->activequeues == NULL)
- event_err(1, "%s: calloc", __func__);
-
- for (i = 0; i < base->nactivequeues; ++i) {
- base->activequeues[i] = malloc(sizeof(struct event_list));
- if (base->activequeues[i] == NULL)
- event_err(1, "%s: malloc", __func__);
- TAILQ_INIT(base->activequeues[i]);
- }
-
- return (0);
-}
-
-int
-event_haveevents(struct event_base *base)
-{
- return (base->event_count > 0);
-}
-
-/*
- * Active events are stored in priority queues. Lower priorities are always
- * process before higher priorities. Low priority events can starve high
- * priority ones.
- */
-
-static void
-event_process_active(struct event_base *base)
-{
- struct event *ev;
- struct event_list *activeq = NULL;
- int i;
- short ncalls;
-
- for (i = 0; i < base->nactivequeues; ++i) {
- if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
- activeq = base->activequeues[i];
- break;
- }
- }
-
- assert(activeq != NULL);
-
- for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
- if (ev->ev_events & EV_PERSIST)
- event_queue_remove(base, ev, EVLIST_ACTIVE);
- else
- event_del(ev);
-
- /* Allows deletes to work */
- ncalls = ev->ev_ncalls;
- ev->ev_pncalls = &ncalls;
- while (ncalls) {
- ncalls--;
- ev->ev_ncalls = ncalls;
- (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
- if (event_gotsig || base->event_break)
- return;
- }
- }
-}
-
-/*
- * Wait continously for events. We exit only if no events are left.
- */
-
-int
-event_dispatch(void)
-{
- return (event_loop(0));
-}
-
-int
-event_base_dispatch(struct event_base *event_base)
-{
- return (event_base_loop(event_base, 0));
-}
-
-const char *
-event_base_get_method(struct event_base *base)
-{
- assert(base);
- return (base->evsel->name);
-}
-
-static void
-event_loopexit_cb(int fd, short what, void *arg)
-{
- struct event_base *base = arg;
- base->event_gotterm = 1;
-}
-
-/* not thread safe */
-int
-event_loopexit(const struct timeval *tv)
-{
- return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
- current_base, tv));
-}
-
-int
-event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
-{
- return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
- event_base, tv));
-}
-
-/* not thread safe */
-int
-event_loopbreak(void)
-{
- return (event_base_loopbreak(current_base));
-}
-
-int
-event_base_loopbreak(struct event_base *event_base)
-{
- if (event_base == NULL)
- return (-1);
-
- event_base->event_break = 1;
- return (0);
-}
-
-
-
-/* not thread safe */
-
-int
-event_loop(int flags)
-{
- return event_base_loop(current_base, flags);
-}
-
-int
-event_base_loop(struct event_base *base, int flags)
-{
- const struct eventop *evsel = base->evsel;
- void *evbase = base->evbase;
- struct timeval tv;
- struct timeval *tv_p;
- int res, done;
-
- /* clear time cache */
- base->tv_cache.tv_sec = 0;
-
- if (base->sig.ev_signal_added)
- evsignal_base = base;
- done = 0;
- while (!done) {
- /* Terminate the loop if we have been asked to */
- if (base->event_gotterm) {
- base->event_gotterm = 0;
- break;
- }
-
- if (base->event_break) {
- base->event_break = 0;
- break;
- }
-
- /* You cannot use this interface for multi-threaded apps */
- while (event_gotsig) {
- event_gotsig = 0;
- if (event_sigcb) {
- res = (*event_sigcb)();
- if (res == -1) {
- errno = EINTR;
- return (-1);
- }
- }
- }
-
- timeout_correct(base, &tv);
-
- tv_p = &tv;
- if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
- timeout_next(base, &tv_p);
- } else {
- /*
- * if we have active events, we just poll new events
- * without waiting.
- */
- evutil_timerclear(&tv);
- }
-
- /* If we have no events, we just exit */
- if (!event_haveevents(base)) {
- event_debug(("%s: no events registered.", __func__));
- return (1);
- }
-
- /* update last old time */
- gettime(base, &base->event_tv);
-
- /* clear time cache */
- base->tv_cache.tv_sec = 0;
-
- res = evsel->dispatch(base, evbase, tv_p);
-
- if (res == -1)
- return (-1);
- gettime(base, &base->tv_cache);
-
- timeout_process(base);
-
- if (base->event_count_active) {
- event_process_active(base);
- if (!base->event_count_active && (flags & EVLOOP_ONCE))
- done = 1;
- } else if (flags & EVLOOP_NONBLOCK)
- done = 1;
- }
-
- /* clear time cache */
- base->tv_cache.tv_sec = 0;
-
- event_debug(("%s: asked to terminate loop.", __func__));
- return (0);
-}
-
-/* Sets up an event for processing once */
-
-struct event_once {
- struct event ev;
-
- void (*cb)(int, short, void *);
- void *arg;
-};
-
-/* One-time callback, it deletes itself */
-
-static void
-event_once_cb(int fd, short events, void *arg)
-{
- struct event_once *eonce = arg;
-
- (*eonce->cb)(fd, events, eonce->arg);
- free(eonce);
-}
-
-/* not threadsafe, event scheduled once. */
-int
-event_once(int fd, short events,
- void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
-{
- return event_base_once(current_base, fd, events, callback, arg, tv);
-}
-
-/* Schedules an event once */
-int
-event_base_once(struct event_base *base, int fd, short events,
- void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
-{
- struct event_once *eonce;
- struct timeval etv;
- int res;
-
- /* We cannot support signals that just fire once */
- if (events & EV_SIGNAL)
- return (-1);
-
- if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
- return (-1);
-
- eonce->cb = callback;
- eonce->arg = arg;
-
- if (events == EV_TIMEOUT) {
- if (tv == NULL) {
- evutil_timerclear(&etv);
- tv = &etv;
- }
-
- evtimer_set(&eonce->ev, event_once_cb, eonce);
- } else if (events & (EV_READ|EV_WRITE)) {
- events &= EV_READ|EV_WRITE;
-
- event_set(&eonce->ev, fd, events, event_once_cb, eonce);
- } else {
- /* Bad event combination */
- free(eonce);
- return (-1);
- }
-
- res = event_base_set(base, &eonce->ev);
- if (res == 0)
- res = event_add(&eonce->ev, tv);
- if (res != 0) {
- free(eonce);
- return (res);
- }
-
- return (0);
-}
-
-void
-event_set(struct event *ev, int fd, short events,
- void (*callback)(int, short, void *), void *arg)
-{
- /* Take the current base - caller needs to set the real base later */
- ev->ev_base = current_base;
-
- ev->ev_callback = callback;
- ev->ev_arg = arg;
- ev->ev_fd = fd;
- ev->ev_events = events;
- ev->ev_res = 0;
- ev->ev_flags = EVLIST_INIT;
- ev->ev_ncalls = 0;
- ev->ev_pncalls = NULL;
-
- min_heap_elem_init(ev);
-
- /* by default, we put new events into the middle priority */
- if(current_base)
- ev->ev_pri = current_base->nactivequeues/2;
-}
-
-int
-event_base_set(struct event_base *base, struct event *ev)
-{
- /* Only innocent events may be assigned to a different base */
- if (ev->ev_flags != EVLIST_INIT)
- return (-1);
-
- ev->ev_base = base;
- ev->ev_pri = base->nactivequeues/2;
-
- return (0);
-}
-
-/*
- * Set's the priority of an event - if an event is already scheduled
- * changing the priority is going to fail.
- */
-
-int
-event_priority_set(struct event *ev, int pri)
-{
- if (ev->ev_flags & EVLIST_ACTIVE)
- return (-1);
- if (pri < 0 || pri >= ev->ev_base->nactivequeues)
- return (-1);
-
- ev->ev_pri = pri;
-
- return (0);
-}
-
-/*
- * Checks if a specific event is pending or scheduled.
- */
-
-int
-event_pending(struct event *ev, short event, struct timeval *tv)
-{
- struct timeval now, res;
- int flags = 0;
-
- if (ev->ev_flags & EVLIST_INSERTED)
- flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
- if (ev->ev_flags & EVLIST_ACTIVE)
- flags |= ev->ev_res;
- if (ev->ev_flags & EVLIST_TIMEOUT)
- flags |= EV_TIMEOUT;
-
- event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
-
- /* See if there is a timeout that we should report */
- if (tv != NULL && (flags & event & EV_TIMEOUT)) {
- gettime(ev->ev_base, &now);
- evutil_timersub(&ev->ev_timeout, &now, &res);
- /* correctly remap to real time */
- evutil_gettimeofday(&now, NULL);
- evutil_timeradd(&now, &res, tv);
- }
-
- return (flags & event);
-}
-
-int
-event_add(struct event *ev, const struct timeval *tv)
-{
- struct event_base *base = ev->ev_base;
- const struct eventop *evsel = base->evsel;
- void *evbase = base->evbase;
- int res = 0;
-
- event_debug((
- "event_add: event: %p, %s%s%scall %p",
- ev,
- ev->ev_events & EV_READ ? "EV_READ " : " ",
- ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
- tv ? "EV_TIMEOUT " : " ",
- ev->ev_callback));
-
- assert(!(ev->ev_flags & ~EVLIST_ALL));
-
- /*
- * prepare for timeout insertion further below, if we get a
- * failure on any step, we should not change any state.
- */
- if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
- if (min_heap_reserve(&base->timeheap,
- 1 + min_heap_size(&base->timeheap)) == -1)
- return (-1); /* ENOMEM == errno */
- }
-
- if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
- !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
- res = evsel->add(evbase, ev);
- if (res != -1)
- event_queue_insert(base, ev, EVLIST_INSERTED);
- }
-
- /*
- * we should change the timout state only if the previous event
- * addition succeeded.
- */
- if (res != -1 && tv != NULL) {
- struct timeval now;
-
- /*
- * we already reserved memory above for the case where we
- * are not replacing an exisiting timeout.
- */
- if (ev->ev_flags & EVLIST_TIMEOUT)
- event_queue_remove(base, ev, EVLIST_TIMEOUT);
-
- /* Check if it is active due to a timeout. Rescheduling
- * this timeout before the callback can be executed
- * removes it from the active list. */
- if ((ev->ev_flags & EVLIST_ACTIVE) &&
- (ev->ev_res & EV_TIMEOUT)) {
- /* See if we are just active executing this
- * event in a loop
- */
- if (ev->ev_ncalls && ev->ev_pncalls) {
- /* Abort loop */
- *ev->ev_pncalls = 0;
- }
-
- event_queue_remove(base, ev, EVLIST_ACTIVE);
- }
-
- gettime(base, &now);
- evutil_timeradd(&now, tv, &ev->ev_timeout);
-
- event_debug((
- "event_add: timeout in %ld seconds, call %p",
- tv->tv_sec, ev->ev_callback));
-
- event_queue_insert(base, ev, EVLIST_TIMEOUT);
- }
-
- return (res);
-}
-
-int
-event_del(struct event *ev)
-{
- struct event_base *base;
- const struct eventop *evsel;
- void *evbase;
-
- event_debug(("event_del: %p, callback %p",
- ev, ev->ev_callback));
-
- /* An event without a base has not been added */
- if (ev->ev_base == NULL)
- return (-1);
-
- base = ev->ev_base;
- evsel = base->evsel;
- evbase = base->evbase;
-
- assert(!(ev->ev_flags & ~EVLIST_ALL));
-
- /* See if we are just active executing this event in a loop */
- if (ev->ev_ncalls && ev->ev_pncalls) {
- /* Abort loop */
- *ev->ev_pncalls = 0;
- }
-
- if (ev->ev_flags & EVLIST_TIMEOUT)
- event_queue_remove(base, ev, EVLIST_TIMEOUT);
-
- if (ev->ev_flags & EVLIST_ACTIVE)
- event_queue_remove(base, ev, EVLIST_ACTIVE);
-
- if (ev->ev_flags & EVLIST_INSERTED) {
- event_queue_remove(base, ev, EVLIST_INSERTED);
- return (evsel->del(evbase, ev));
- }
-
- return (0);
-}
-
-void
-event_active(struct event *ev, int res, short ncalls)
-{
- /* We get different kinds of events, add them together */
- if (ev->ev_flags & EVLIST_ACTIVE) {
- ev->ev_res |= res;
- return;
- }
-
- ev->ev_res = res;
- ev->ev_ncalls = ncalls;
- ev->ev_pncalls = NULL;
- event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
-}
-
-static int
-timeout_next(struct event_base *base, struct timeval **tv_p)
-{
- struct timeval now;
- struct event *ev;
- struct timeval *tv = *tv_p;
-
- if ((ev = min_heap_top(&base->timeheap)) == NULL) {
- /* if no time-based events are active wait for I/O */
- *tv_p = NULL;
- return (0);
- }
-
- if (gettime(base, &now) == -1)
- return (-1);
-
- if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
- evutil_timerclear(tv);
- return (0);
- }
-
- evutil_timersub(&ev->ev_timeout, &now, tv);
-
- assert(tv->tv_sec >= 0);
- assert(tv->tv_usec >= 0);
-
- event_debug(("timeout_next: in %ld seconds", tv->tv_sec));
- return (0);
-}
-
-/*
- * Determines if the time is running backwards by comparing the current
- * time against the last time we checked. Not needed when using clock
- * monotonic.
- */
-
-static void
-timeout_correct(struct event_base *base, struct timeval *tv)
-{
- struct event **pev;
- unsigned int size;
- struct timeval off;
-
- if (use_monotonic)
- return;
-
- /* Check if time is running backwards */
- gettime(base, tv);
- if (evutil_timercmp(tv, &base->event_tv, >=)) {
- base->event_tv = *tv;
- return;
- }
-
- event_debug(("%s: time is running backwards, corrected",
- __func__));
- evutil_timersub(&base->event_tv, tv, &off);
-
- /*
- * We can modify the key element of the node without destroying
- * the key, beause we apply it to all in the right order.
- */
- pev = base->timeheap.p;
- size = base->timeheap.n;
- for (; size-- > 0; ++pev) {
- struct timeval *ev_tv = &(**pev).ev_timeout;
- evutil_timersub(ev_tv, &off, ev_tv);
- }
-}
-
-void
-timeout_process(struct event_base *base)
-{
- struct timeval now;
- struct event *ev;
-
- if (min_heap_empty(&base->timeheap))
- return;
-
- gettime(base, &now);
-
- while ((ev = min_heap_top(&base->timeheap))) {
- if (evutil_timercmp(&ev->ev_timeout, &now, >))
- break;
-
- /* delete this event from the I/O queues */
- event_del(ev);
-
- event_debug(("timeout_process: call %p",
- ev->ev_callback));
- event_active(ev, EV_TIMEOUT, 1);
- }
-}
-
-void
-event_queue_remove(struct event_base *base, struct event *ev, int queue)
-{
- if (!(ev->ev_flags & queue))
- event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
- ev, ev->ev_fd, queue);
-
- if (~ev->ev_flags & EVLIST_INTERNAL)
- base->event_count--;
-
- ev->ev_flags &= ~queue;
- switch (queue) {
- case EVLIST_INSERTED:
- TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
- break;
- case EVLIST_ACTIVE:
- base->event_count_active--;
- TAILQ_REMOVE(base->activequeues[ev->ev_pri],
- ev, ev_active_next);
- break;
- case EVLIST_TIMEOUT:
- min_heap_erase(&base->timeheap, ev);
- break;
- default:
- event_errx(1, "%s: unknown queue %x", __func__, queue);
- }
-}
-
-void
-event_queue_insert(struct event_base *base, struct event *ev, int queue)
-{
- if (ev->ev_flags & queue) {
- /* Double insertion is possible for active events */
- if (queue & EVLIST_ACTIVE)
- return;
-
- event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
- ev, ev->ev_fd, queue);
- }
-
- if (~ev->ev_flags & EVLIST_INTERNAL)
- base->event_count++;
-
- ev->ev_flags |= queue;
- switch (queue) {
- case EVLIST_INSERTED:
- TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
- break;
- case EVLIST_ACTIVE:
- base->event_count_active++;
- TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
- ev,ev_active_next);
- break;
- case EVLIST_TIMEOUT: {
- min_heap_push(&base->timeheap, ev);
- break;
- }
- default:
- event_errx(1, "%s: unknown queue %x", __func__, queue);
- }
-}
-
-/* Functions for debugging */
-
-const char *
-event_get_version(void)
-{
- return (VERSION);
-}
-
-/*
- * No thread-safe interface needed - the information should be the same
- * for all threads.
- */
-
-const char *
-event_get_method(void)
-{
- return (current_base->evsel->name);
-}
diff --git a/lib/libevent/event.h b/lib/libevent/event.h
deleted file mode 100644
index 6a1a9ecda8a..00000000000
--- a/lib/libevent/event.h
+++ /dev/null
@@ -1,1163 +0,0 @@
-/* $NetBSD: event.h,v 1.7 2009/08/19 15:18:05 tls Exp $ */
-/* $OpenBSD: event.h,v 1.4 2002/07/12 18:50:48 provos Exp $ */
-
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVENT_H_
-#define _EVENT_H_
-
-/** @mainpage
-
- @section intro Introduction
-
- libevent is an event notification library for developing scalable network
- servers. The libevent API provides a mechanism to execute a callback
- function when a specific event occurs on a file descriptor or after a
- timeout has been reached. Furthermore, libevent also support callbacks due
- to signals or regular timeouts.
-
- libevent is meant to replace the event loop found in event driven network
- servers. An application just needs to call event_dispatch() and then add or
- remove events dynamically without having to change the event loop.
-
- Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and
- epoll(4). It also has experimental support for real-time signals. The
- internal event mechanism is completely independent of the exposed event API,
- and a simple update of libevent can provide new functionality without having
- to redesign the applications. As a result, Libevent allows for portable
- application development and provides the most scalable event notification
- mechanism available on an operating system. Libevent can also be used for
- multi-threaded aplications; see Steven Grimm's explanation. Libevent should
- compile on Linux, *BSD, Mac OS X, Solaris and Windows.
-
- @section usage Standard usage
-
- Every program that uses libevent must include the <event.h> header, and pass
- the -levent flag to the linker. Before using any of the functions in the
- library, you must call event_init() or event_base_new() to perform one-time
- initialization of the libevent library.
-
- @section event Event notification
-
- For each file descriptor that you wish to monitor, you must declare an event
- structure and call event_set() to initialize the members of the structure.
- To enable notification, you add the structure to the list of monitored
- events by calling event_add(). The event structure must remain allocated as
- long as it is active, so it should be allocated on the heap. Finally, you
- call event_dispatch() to loop and dispatch events.
-
- @section bufferevent I/O Buffers
-
- libevent provides an abstraction on top of the regular event callbacks. This
- abstraction is called a buffered event. A buffered event provides input and
- output buffers that get filled and drained automatically. The user of a
- buffered event no longer deals directly with the I/O, but instead is reading
- from input and writing to output buffers.
-
- Once initialized via bufferevent_new(), the bufferevent structure can be
- used repeatedly with bufferevent_enable() and bufferevent_disable().
- Instead of reading and writing directly to a socket, you would call
- bufferevent_read() and bufferevent_write().
-
- When read enabled the bufferevent will try to read from the file descriptor
- and call the read callback. The write callback is executed whenever the
- output buffer is drained below the write low watermark, which is 0 by
- default.
-
- @section timers Timers
-
- libevent can also be used to create timers that invoke a callback after a
- certain amount of time has expired. The evtimer_set() function prepares an
- event struct to be used as a timer. To activate the timer, call
- evtimer_add(). Timers can be deactivated by calling evtimer_del().
-
- @section timeouts Timeouts
-
- In addition to simple timers, libevent can assign timeout events to file
- descriptors that are triggered whenever a certain amount of time has passed
- with no activity on a file descriptor. The timeout_set() function
- initializes an event struct for use as a timeout. Once initialized, the
- event must be activated by using timeout_add(). To cancel the timeout, call
- timeout_del().
-
- @section evdns Asynchronous DNS resolution
-
- libevent provides an asynchronous DNS resolver that should be used instead
- of the standard DNS resolver functions. These functions can be imported by
- including the <evdns.h> header in your program. Before using any of the
- resolver functions, you must call evdns_init() to initialize the library. To
- convert a hostname to an IP address, you call the evdns_resolve_ipv4()
- function. To perform a reverse lookup, you would call the
- evdns_resolve_reverse() function. All of these functions use callbacks to
- avoid blocking while the lookup is performed.
-
- @section evhttp Event-driven HTTP servers
-
- libevent provides a very simple event-driven HTTP server that can be
- embedded in your program and used to service HTTP requests.
-
- To use this capability, you need to include the <evhttp.h> header in your
- program. You create the server by calling evhttp_new(). Add addresses and
- ports to listen on with evhttp_bind_socket(). You then register one or more
- callbacks to handle incoming requests. Each URI can be assigned a callback
- via the evhttp_set_cb() function. A generic callback function can also be
- registered via evhttp_set_gencb(); this callback will be invoked if no other
- callbacks have been registered for a given URI.
-
- @section evrpc A framework for RPC servers and clients
-
- libevents provides a framework for creating RPC servers and clients. It
- takes care of marshaling and unmarshaling all data structures.
-
- @section api API Reference
-
- To browse the complete documentation of the libevent API, click on any of
- the following links.
-
- event.h
- The primary libevent header
-
- evdns.h
- Asynchronous DNS resolution
-
- evhttp.h
- An embedded libevent-based HTTP server
-
- evrpc.h
- A framework for creating RPC servers and clients
-
- */
-
-/** @file event.h
-
- A library for writing event-driven network servers
-
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <event-config.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdint.h>
-#include <stdarg.h>
-
-/* For int types. */
-#include <evutil.h>
-
-#define EVLIST_TIMEOUT 0x01
-#define EVLIST_INSERTED 0x02
-#define EVLIST_SIGNAL 0x04
-#define EVLIST_ACTIVE 0x08
-#define EVLIST_INTERNAL 0x10
-#define EVLIST_INIT 0x80
-
-/* EVLIST_X_ Private space: 0x1000-0xf000 */
-#define EVLIST_ALL (0xf000 | 0x9f)
-
-#define EV_TIMEOUT 0x01
-#define EV_READ 0x02
-#define EV_WRITE 0x04
-#define EV_SIGNAL 0x08
-#define EV_PERSIST 0x10 /* Persistant event */
-
-/* Fix so that ppl dont have to run with <sys/queue.h> */
-#ifndef TAILQ_ENTRY
-#define _EVENT_DEFINED_TQENTRY
-#define TAILQ_ENTRY(type) \
-struct { \
- struct type *tqe_next; /* next element */ \
- struct type **tqe_prev; /* address of previous next element */ \
-}
-#endif /* !TAILQ_ENTRY */
-
-struct event_base;
-struct event {
- TAILQ_ENTRY (event) ev_next;
- TAILQ_ENTRY (event) ev_active_next;
- TAILQ_ENTRY (event) ev_signal_next;
- unsigned int min_heap_idx; /* for managing timeouts */
-
- struct event_base *ev_base;
-
- int ev_fd;
- short ev_events;
- short ev_ncalls;
- short *ev_pncalls; /* Allows deletes in callback */
-
- struct timeval ev_timeout;
-
- int ev_pri; /* smaller numbers are higher priority */
-
- void (*ev_callback)(int, short, void *arg);
- void *ev_arg;
-
- int ev_res; /* result passed to event callback */
- int ev_flags;
-};
-
-#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd
-#define EVENT_FD(ev) (int)(ev)->ev_fd
-
-/*
- * Key-Value pairs. Can be used for HTTP headers but also for
- * query argument parsing.
- */
-struct evkeyval {
- TAILQ_ENTRY(evkeyval) next;
-
- char *key;
- char *value;
-};
-
-#ifdef _EVENT_DEFINED_TQENTRY
-#undef TAILQ_ENTRY
-struct event_list;
-struct evkeyvalq;
-#undef _EVENT_DEFINED_TQENTRY
-#else
-TAILQ_HEAD (event_list, event);
-TAILQ_HEAD (evkeyvalq, evkeyval);
-#endif /* _EVENT_DEFINED_TQENTRY */
-
-/**
- Initialize the event API.
-
- Use event_base_new() to initialize a new event base, but does not set
- the current_base global. If using only event_base_new(), each event
- added must have an event base set with event_base_set()
-
- @see event_base_set(), event_base_free(), event_init()
- */
-struct event_base *event_base_new(void);
-
-/**
- Initialize the event API.
-
- The event API needs to be initialized with event_init() before it can be
- used. Sets the current_base global representing the default base for
- events that have no base associated with them.
-
- @see event_base_set(), event_base_new()
- */
-struct event_base *event_init(void);
-
-/**
- Reinitialized the event base after a fork
-
- Some event mechanisms do not survive across fork. The event base needs
- to be reinitialized with the event_reinit() function.
-
- @param base the event base that needs to be re-initialized
- @return 0 if successful, or -1 if some events could not be re-added.
- @see event_base_new(), event_init()
-*/
-int event_reinit(struct event_base *base);
-
-/**
- Loop to process events.
-
- In order to process events, an application needs to call
- event_dispatch(). This function only returns on error, and should
- replace the event core of the application program.
-
- @see event_base_dispatch()
- */
-int event_dispatch(void);
-
-
-/**
- Threadsafe event dispatching loop.
-
- @param eb the event_base structure returned by event_init()
- @see event_init(), event_dispatch()
- */
-int event_base_dispatch(struct event_base *);
-
-
-/**
- Get the kernel event notification mechanism used by libevent.
-
- @param eb the event_base structure returned by event_base_new()
- @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
- */
-const char *event_base_get_method(struct event_base *);
-
-
-/**
- Deallocate all memory associated with an event_base, and free the base.
-
- Note that this function will not close any fds or free any memory passed
- to event_set as the argument to callback.
-
- @param eb an event_base to be freed
- */
-void event_base_free(struct event_base *);
-
-
-#define _EVENT_LOG_DEBUG 0
-#define _EVENT_LOG_MSG 1
-#define _EVENT_LOG_WARN 2
-#define _EVENT_LOG_ERR 3
-typedef void (*event_log_cb)(int severity, const char *msg);
-/**
- Redirect libevent's log messages.
-
- @param cb a function taking two arguments: an integer severity between
- _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string. If cb is NULL,
- then the default log is used.
- */
-void event_set_log_callback(event_log_cb cb);
-
-/**
- Associate a different event base with an event.
-
- @param eb the event base
- @param ev the event
- */
-int event_base_set(struct event_base *, struct event *);
-
-/**
- event_loop() flags
- */
-/*@{*/
-#define EVLOOP_ONCE 0x01 /**< Block at most once. */
-#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */
-/*@}*/
-
-/**
- Handle events.
-
- This is a more flexible version of event_dispatch().
-
- @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
- @return 0 if successful, -1 if an error occurred, or 1 if no events were
- registered.
- @see event_loopexit(), event_base_loop()
-*/
-int event_loop(int);
-
-/**
- Handle events (threadsafe version).
-
- This is a more flexible version of event_base_dispatch().
-
- @param eb the event_base structure returned by event_init()
- @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
- @return 0 if successful, -1 if an error occurred, or 1 if no events were
- registered.
- @see event_loopexit(), event_base_loop()
- */
-int event_base_loop(struct event_base *, int);
-
-/**
- Exit the event loop after the specified time.
-
- The next event_loop() iteration after the given timer expires will
- complete normally (handling all queued events) then exit without
- blocking for events again.
-
- Subsequent invocations of event_loop() will proceed normally.
-
- @param tv the amount of time after which the loop should terminate.
- @return 0 if successful, or -1 if an error occurred
- @see event_loop(), event_base_loop(), event_base_loopexit()
- */
-int event_loopexit(const struct timeval *);
-
-
-/**
- Exit the event loop after the specified time (threadsafe variant).
-
- The next event_base_loop() iteration after the given timer expires will
- complete normally (handling all queued events) then exit without
- blocking for events again.
-
- Subsequent invocations of event_base_loop() will proceed normally.
-
- @param eb the event_base structure returned by event_init()
- @param tv the amount of time after which the loop should terminate.
- @return 0 if successful, or -1 if an error occurred
- @see event_loopexit()
- */
-int event_base_loopexit(struct event_base *, const struct timeval *);
-
-/**
- Abort the active event_loop() immediately.
-
- event_loop() will abort the loop after the next event is completed;
- event_loopbreak() is typically invoked from this event's callback.
- This behavior is analogous to the "break;" statement.
-
- Subsequent invocations of event_loop() will proceed normally.
-
- @return 0 if successful, or -1 if an error occurred
- @see event_base_loopbreak(), event_loopexit()
- */
-int event_loopbreak(void);
-
-/**
- Abort the active event_base_loop() immediately.
-
- event_base_loop() will abort the loop after the next event is completed;
- event_base_loopbreak() is typically invoked from this event's callback.
- This behavior is analogous to the "break;" statement.
-
- Subsequent invocations of event_loop() will proceed normally.
-
- @param eb the event_base structure returned by event_init()
- @return 0 if successful, or -1 if an error occurred
- @see event_base_loopexit
- */
-int event_base_loopbreak(struct event_base *);
-
-
-/**
- Add a timer event.
-
- @param ev the event struct
- @param tv timeval struct
- */
-#define evtimer_add(ev, tv) event_add(ev, tv)
-
-
-/**
- Define a timer event.
-
- @param ev event struct to be modified
- @param cb callback function
- @param arg argument that will be passed to the callback function
- */
-#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
-
-
-/**
- * Delete a timer event.
- *
- * @param ev the event struct to be disabled
- */
-#define evtimer_del(ev) event_del(ev)
-#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
-#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
-
-/**
- * Add a timeout event.
- *
- * @param ev the event struct to be disabled
- * @param tv the timeout value, in seconds
- */
-#define timeout_add(ev, tv) event_add(ev, tv)
-
-
-/**
- * Define a timeout event.
- *
- * @param ev the event struct to be defined
- * @param cb the callback to be invoked when the timeout expires
- * @param arg the argument to be passed to the callback
- */
-#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
-
-
-/**
- * Disable a timeout event.
- *
- * @param ev the timeout event to be disabled
- */
-#define timeout_del(ev) event_del(ev)
-
-#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
-#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
-
-#define signal_add(ev, tv) event_add(ev, tv)
-#define signal_set(ev, x, cb, arg) \
- event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
-#define signal_del(ev) event_del(ev)
-#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv)
-#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
-
-/**
- Prepare an event structure to be added.
-
- The function event_set() prepares the event structure ev to be used in
- future calls to event_add() and event_del(). The event will be prepared to
- call the function specified by the fn argument with an int argument
- indicating the file descriptor, a short argument indicating the type of
- event, and a void * argument given in the arg argument. The fd indicates
- the file descriptor that should be monitored for events. The events can be
- either EV_READ, EV_WRITE, or both. Indicating that an application can read
- or write from the file descriptor respectively without blocking.
-
- The function fn will be called with the file descriptor that triggered the
- event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL,
- EV_READ, or EV_WRITE. The additional flag EV_PERSIST makes an event_add()
- persistent until event_del() has been called.
-
- @param ev an event struct to be modified
- @param fd the file descriptor to be monitored
- @param event desired events to monitor; can be EV_READ and/or EV_WRITE
- @param fn callback function to be invoked when the event occurs
- @param arg an argument to be passed to the callback function
-
- @see event_add(), event_del(), event_once()
-
- */
-void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
-
-/**
- Schedule a one-time event to occur.
-
- The function event_once() is similar to event_set(). However, it schedules
- a callback to be called exactly once and does not require the caller to
- prepare an event structure.
-
- @param fd a file descriptor to monitor
- @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
- EV_WRITE
- @param callback callback function to be invoked when the event occurs
- @param arg an argument to be passed to the callback function
- @param timeout the maximum amount of time to wait for the event, or NULL
- to wait forever
- @return 0 if successful, or -1 if an error occurred
- @see event_set()
-
- */
-int event_once(int, short, void (*)(int, short, void *), void *,
- const struct timeval *);
-
-
-/**
- Schedule a one-time event (threadsafe variant)
-
- The function event_base_once() is similar to event_set(). However, it
- schedules a callback to be called exactly once and does not require the
- caller to prepare an event structure.
-
- @param base an event_base returned by event_init()
- @param fd a file descriptor to monitor
- @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
- EV_WRITE
- @param callback callback function to be invoked when the event occurs
- @param arg an argument to be passed to the callback function
- @param timeout the maximum amount of time to wait for the event, or NULL
- to wait forever
- @return 0 if successful, or -1 if an error occurred
- @see event_once()
- */
-int event_base_once(struct event_base *base, int fd, short events,
- void (*callback)(int, short, void *), void *arg,
- const struct timeval *timeout);
-
-
-/**
- Add an event to the set of monitored events.
-
- The function event_add() schedules the execution of the ev event when the
- event specified in event_set() occurs or in at least the time specified in
- the tv. If tv is NULL, no timeout occurs and the function will only be
- called if a matching event occurs on the file descriptor. The event in the
- ev argument must be already initialized by event_set() and may not be used
- in calls to event_set() until it has timed out or been removed with
- event_del(). If the event in the ev argument already has a scheduled
- timeout, the old timeout will be replaced by the new one.
-
- @param ev an event struct initialized via event_set()
- @param timeout the maximum amount of time to wait for the event, or NULL
- to wait forever
- @return 0 if successful, or -1 if an error occurred
- @see event_del(), event_set()
- */
-int event_add(struct event *ev, const struct timeval *timeout);
-
-
-/**
- Remove an event from the set of monitored events.
-
- The function event_del() will cancel the event in the argument ev. If the
- event has already executed or has never been added the call will have no
- effect.
-
- @param ev an event struct to be removed from the working set
- @return 0 if successful, or -1 if an error occurred
- @see event_add()
- */
-int event_del(struct event *);
-
-void event_active(struct event *, int, short);
-
-
-/**
- Checks if a specific event is pending or scheduled.
-
- @param ev an event struct previously passed to event_add()
- @param event the requested event type; any of EV_TIMEOUT|EV_READ|
- EV_WRITE|EV_SIGNAL
- @param tv an alternate timeout (FIXME - is this true?)
-
- @return 1 if the event is pending, or 0 if the event has not occurred
-
- */
-int event_pending(struct event *ev, short event, struct timeval *tv);
-
-
-/**
- Test if an event structure has been initialized.
-
- The event_initialized() macro can be used to check if an event has been
- initialized.
-
- @param ev an event structure to be tested
- @return 1 if the structure has been initialized, or 0 if it has not been
- initialized
- */
-#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
-
-
-/**
- Get the libevent version number.
-
- @return a string containing the version number of libevent
- */
-const char *event_get_version(void);
-
-
-/**
- Get the kernel event notification mechanism used by libevent.
-
- @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
- */
-const char *event_get_method(void);
-
-
-/**
- Set the number of different event priorities.
-
- By default libevent schedules all active events with the same priority.
- However, some time it is desirable to process some events with a higher
- priority than others. For that reason, libevent supports strict priority
- queues. Active events with a lower priority are always processed before
- events with a higher priority.
-
- The number of different priorities can be set initially with the
- event_priority_init() function. This function should be called before the
- first call to event_dispatch(). The event_priority_set() function can be
- used to assign a priority to an event. By default, libevent assigns the
- middle priority to all events unless their priority is explicitly set.
-
- @param npriorities the maximum number of priorities
- @return 0 if successful, or -1 if an error occurred
- @see event_base_priority_init(), event_priority_set()
-
- */
-int event_priority_init(int);
-
-
-/**
- Set the number of different event priorities (threadsafe variant).
-
- See the description of event_priority_init() for more information.
-
- @param eb the event_base structure returned by event_init()
- @param npriorities the maximum number of priorities
- @return 0 if successful, or -1 if an error occurred
- @see event_priority_init(), event_priority_set()
- */
-int event_base_priority_init(struct event_base *, int);
-
-
-/**
- Assign a priority to an event.
-
- @param ev an event struct
- @param priority the new priority to be assigned
- @return 0 if successful, or -1 if an error occurred
- @see event_priority_init()
- */
-int event_priority_set(struct event *, int);
-
-
-/* These functions deal with buffering input and output */
-
-struct evbuffer {
- u_char *buffer;
- u_char *orig_buffer;
-
- size_t misalign;
- size_t totallen;
- size_t off;
-
- void (*cb)(struct evbuffer *, size_t, size_t, void *);
- void *cbarg;
-};
-
-/* Just for error reporting - use other constants otherwise */
-#define EVBUFFER_READ 0x01
-#define EVBUFFER_WRITE 0x02
-#define EVBUFFER_EOF 0x10
-#define EVBUFFER_ERROR 0x20
-#define EVBUFFER_TIMEOUT 0x40
-
-struct bufferevent;
-typedef void (*evbuffercb)(struct bufferevent *, void *);
-typedef void (*everrorcb)(struct bufferevent *, short what, void *);
-
-struct event_watermark {
- size_t low;
- size_t high;
-};
-
-struct bufferevent {
- struct event_base *ev_base;
-
- struct event ev_read;
- struct event ev_write;
-
- struct evbuffer *input;
- struct evbuffer *output;
-
- struct event_watermark wm_read;
- struct event_watermark wm_write;
-
- evbuffercb readcb;
- evbuffercb writecb;
- everrorcb errorcb;
- void *cbarg;
-
- int timeout_read; /* in seconds */
- int timeout_write; /* in seconds */
-
- short enabled; /* events that are currently enabled */
-};
-
-
-/**
- Create a new bufferevent.
-
- libevent provides an abstraction on top of the regular event callbacks.
- This abstraction is called a buffered event. A buffered event provides
- input and output buffers that get filled and drained automatically. The
- user of a buffered event no longer deals directly with the I/O, but
- instead is reading from input and writing to output buffers.
-
- Once initialized, the bufferevent structure can be used repeatedly with
- bufferevent_enable() and bufferevent_disable().
-
- When read enabled the bufferevent will try to read from the file descriptor
- and call the read callback. The write callback is executed whenever the
- output buffer is drained below the write low watermark, which is 0 by
- default.
-
- If multiple bases are in use, bufferevent_base_set() must be called before
- enabling the bufferevent for the first time.
-
- @param fd the file descriptor from which data is read and written to.
- This file descriptor is not allowed to be a pipe(2).
- @param readcb callback to invoke when there is data to be read, or NULL if
- no callback is desired
- @param writecb callback to invoke when the file descriptor is ready for
- writing, or NULL if no callback is desired
- @param errorcb callback to invoke when there is an error on the file
- descriptor
- @param cbarg an argument that will be supplied to each of the callbacks
- (readcb, writecb, and errorcb)
- @return a pointer to a newly allocated bufferevent struct, or NULL if an
- error occurred
- @see bufferevent_base_set(), bufferevent_free()
- */
-struct bufferevent *bufferevent_new(int fd,
- evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
-
-
-/**
- Assign a bufferevent to a specific event_base.
-
- @param base an event_base returned by event_init()
- @param bufev a bufferevent struct returned by bufferevent_new()
- @return 0 if successful, or -1 if an error occurred
- @see bufferevent_new()
- */
-int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
-
-
-/**
- Assign a priority to a bufferevent.
-
- @param bufev a bufferevent struct
- @param pri the priority to be assigned
- @return 0 if successful, or -1 if an error occurred
- */
-int bufferevent_priority_set(struct bufferevent *bufev, int pri);
-
-
-/**
- Deallocate the storage associated with a bufferevent structure.
-
- @param bufev the bufferevent structure to be freed.
- */
-void bufferevent_free(struct bufferevent *bufev);
-
-
-/**
- Changes the callbacks for a bufferevent.
-
- @param bufev the bufferevent object for which to change callbacks
- @param readcb callback to invoke when there is data to be read, or NULL if
- no callback is desired
- @param writecb callback to invoke when the file descriptor is ready for
- writing, or NULL if no callback is desired
- @param errorcb callback to invoke when there is an error on the file
- descriptor
- @param cbarg an argument that will be supplied to each of the callbacks
- (readcb, writecb, and errorcb)
- @see bufferevent_new()
- */
-void bufferevent_setcb(struct bufferevent *bufev,
- evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
-
-/**
- Changes the file descriptor on which the bufferevent operates.
-
- @param bufev the bufferevent object for which to change the file descriptor
- @param fd the file descriptor to operate on
-*/
-void bufferevent_setfd(struct bufferevent *bufev, int fd);
-
-/**
- Write data to a bufferevent buffer.
-
- The bufferevent_write() function can be used to write data to the file
- descriptor. The data is appended to the output buffer and written to the
- descriptor automatically as it becomes available for writing.
-
- @param bufev the bufferevent to be written to
- @param data a pointer to the data to be written
- @param size the length of the data, in bytes
- @return 0 if successful, or -1 if an error occurred
- @see bufferevent_write_buffer()
- */
-int bufferevent_write(struct bufferevent *bufev,
- const void *data, size_t size);
-
-
-/**
- Write data from an evbuffer to a bufferevent buffer. The evbuffer is
- being drained as a result.
-
- @param bufev the bufferevent to be written to
- @param buf the evbuffer to be written
- @return 0 if successful, or -1 if an error occurred
- @see bufferevent_write()
- */
-int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
-
-
-/**
- Read data from a bufferevent buffer.
-
- The bufferevent_read() function is used to read data from the input buffer.
-
- @param bufev the bufferevent to be read from
- @param data pointer to a buffer that will store the data
- @param size the size of the data buffer, in bytes
- @return the amount of data read, in bytes.
- */
-size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
-
-/**
- Enable a bufferevent.
-
- @param bufev the bufferevent to be enabled
- @param event any combination of EV_READ | EV_WRITE.
- @return 0 if successful, or -1 if an error occurred
- @see bufferevent_disable()
- */
-int bufferevent_enable(struct bufferevent *bufev, short event);
-
-
-/**
- Disable a bufferevent.
-
- @param bufev the bufferevent to be disabled
- @param event any combination of EV_READ | EV_WRITE.
- @return 0 if successful, or -1 if an error occurred
- @see bufferevent_enable()
- */
-int bufferevent_disable(struct bufferevent *bufev, short event);
-
-
-/**
- Set the read and write timeout for a buffered event.
-
- @param bufev the bufferevent to be modified
- @param timeout_read the read timeout
- @param timeout_write the write timeout
- */
-void bufferevent_settimeout(struct bufferevent *bufev,
- int timeout_read, int timeout_write);
-
-
-/**
- Sets the watermarks for read and write events.
-
- On input, a bufferevent does not invoke the user read callback unless
- there is at least low watermark data in the buffer. If the read buffer
- is beyond the high watermark, the buffevent stops reading from the network.
-
- On output, the user write callback is invoked whenever the buffered data
- falls below the low watermark.
-
- @param bufev the bufferevent to be modified
- @param events EV_READ, EV_WRITE or both
- @param lowmark the lower watermark to set
- @param highmark the high watermark to set
-*/
-
-void bufferevent_setwatermark(struct bufferevent *bufev, short events,
- size_t lowmark, size_t highmark);
-
-#define EVBUFFER_LENGTH(x) (x)->off
-#define EVBUFFER_DATA(x) (x)->buffer
-#define EVBUFFER_INPUT(x) (x)->input
-#define EVBUFFER_OUTPUT(x) (x)->output
-
-
-/**
- Allocate storage for a new evbuffer.
-
- @return a pointer to a newly allocated evbuffer struct, or NULL if an error
- occurred
- */
-struct evbuffer *evbuffer_new(void);
-
-
-/**
- Deallocate storage for an evbuffer.
-
- @param pointer to the evbuffer to be freed
- */
-void evbuffer_free(struct evbuffer *);
-
-
-/**
- Expands the available space in an event buffer.
-
- Expands the available space in the event buffer to at least datlen
-
- @param buf the event buffer to be expanded
- @param datlen the new minimum length requirement
- @return 0 if successful, or -1 if an error occurred
-*/
-int evbuffer_expand(struct evbuffer *, size_t);
-
-
-/**
- Append data to the end of an evbuffer.
-
- @param buf the event buffer to be appended to
- @param data pointer to the beginning of the data buffer
- @param datlen the number of bytes to be copied from the data buffer
- */
-int evbuffer_add(struct evbuffer *, const void *, size_t);
-
-
-
-/**
- Read data from an event buffer and drain the bytes read.
-
- @param buf the event buffer to be read from
- @param data the destination buffer to store the result
- @param datlen the maximum size of the destination buffer
- @return the number of bytes read
- */
-int evbuffer_remove(struct evbuffer *, void *, size_t);
-
-
-/**
- * Read a single line from an event buffer.
- *
- * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
- * The returned buffer needs to be freed by the caller.
- *
- * @param buffer the evbuffer to read from
- * @return pointer to a single line, or NULL if an error occurred
- */
-char *evbuffer_readline(struct evbuffer *);
-
-
-/**
- Move data from one evbuffer into another evbuffer.
-
- This is a destructive add. The data from one buffer moves into
- the other buffer. The destination buffer is expanded as needed.
-
- @param outbuf the output buffer
- @param inbuf the input buffer
- @return 0 if successful, or -1 if an error occurred
- */
-int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
-
-
-/**
- Append a formatted string to the end of an evbuffer.
-
- @param buf the evbuffer that will be appended to
- @param fmt a format string
- @param ... arguments that will be passed to printf(3)
- @return The number of bytes added if successful, or -1 if an error occurred.
- */
-int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...)
-#ifdef __GNUC__
- __attribute__((format(printf, 2, 3)))
-#endif
-;
-
-
-/**
- Append a va_list formatted string to the end of an evbuffer.
-
- @param buf the evbuffer that will be appended to
- @param fmt a format string
- @param ap a varargs va_list argument array that will be passed to vprintf(3)
- @return The number of bytes added if successful, or -1 if an error occurred.
- */
-int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
-
-
-/**
- Remove a specified number of bytes data from the beginning of an evbuffer.
-
- @param buf the evbuffer to be drained
- @param len the number of bytes to drain from the beginning of the buffer
- */
-void evbuffer_drain(struct evbuffer *, size_t);
-
-
-/**
- Write the contents of an evbuffer to a file descriptor.
-
- The evbuffer will be drained after the bytes have been successfully written.
-
- @param buffer the evbuffer to be written and drained
- @param fd the file descriptor to be written to
- @return the number of bytes written, or -1 if an error occurred
- @see evbuffer_read()
- */
-int evbuffer_write(struct evbuffer *, int);
-
-
-/**
- Read from a file descriptor and store the result in an evbuffer.
-
- @param buf the evbuffer to store the result
- @param fd the file descriptor to read from
- @param howmuch the number of bytes to be read
- @return the number of bytes read, or -1 if an error occurred
- @see evbuffer_write()
- */
-int evbuffer_read(struct evbuffer *, int, int);
-
-
-/**
- Find a string within an evbuffer.
-
- @param buffer the evbuffer to be searched
- @param what the string to be searched for
- @param len the length of the search string
- @return a pointer to the beginning of the search string, or NULL if the search failed.
- */
-u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
-
-/**
- Set a callback to invoke when the evbuffer is modified.
-
- @param buffer the evbuffer to be monitored
- @param cb the callback function to invoke when the evbuffer is modified
- @param cbarg an argument to be provided to the callback function
- */
-void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
-
-/*
- * Marshaling tagged data - We assume that all tags are inserted in their
- * numeric order - so that unknown tags will always be higher than the
- * known ones - and we can just ignore the end of an event buffer.
- */
-
-void evtag_init(void);
-
-void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
- ev_uint32_t len);
-
-/**
- Encode an integer and store it in an evbuffer.
-
- We encode integer's by nibbles; the first nibble contains the number
- of significant nibbles - 1; this allows us to encode up to 64-bit
- integers. This function is byte-order independent.
-
- @param evbuf evbuffer to store the encoded number
- @param number a 32-bit integer
- */
-void encode_int(struct evbuffer *evbuf, ev_uint32_t number);
-
-void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
- ev_uint32_t integer);
-
-void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
- const char *string);
-
-void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
- struct timeval *tv);
-
-int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
- struct evbuffer *dst);
-int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
-int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
-int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
-int evtag_consume(struct evbuffer *evbuf);
-
-int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
- ev_uint32_t *pinteger);
-
-int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
- void *data, size_t len);
-
-int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
- char **pstring);
-
-int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
- struct timeval *ptv);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _EVENT_H_ */
diff --git a/lib/libevent/event_tagging.c b/lib/libevent/event_tagging.c
deleted file mode 100644
index 73701eb8030..00000000000
--- a/lib/libevent/event_tagging.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/* $NetBSD: event_tagging.c,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2003, 2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#include <sys/ioctl.h>
-
-#include <sys/queue.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "event.h"
-#include "evutil.h"
-#include "log.h"
-
-int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
-int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
-int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
-
-static struct evbuffer *_buf; /* not thread safe */
-
-void
-evtag_init(void)
-{
- if (_buf != NULL)
- return;
-
- if ((_buf = evbuffer_new()) == NULL)
- event_err(1, "%s: malloc", __func__);
-}
-
-/*
- * We encode integer's by nibbles; the first nibble contains the number
- * of significant nibbles - 1; this allows us to encode up to 64-bit
- * integers. This function is byte-order independent.
- */
-
-void
-encode_int(struct evbuffer *evbuf, ev_uint32_t number)
-{
- int off = 1, nibbles = 0;
- ev_uint8_t data[5];
-
- memset(data, 0, sizeof(ev_uint32_t)+1);
- while (number) {
- if (off & 0x1)
- data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
- else
- data[off/2] = (data[off/2] & 0x0f) |
- ((number & 0x0f) << 4);
- number >>= 4;
- off++;
- }
-
- if (off > 2)
- nibbles = off - 2;
-
- /* Off - 1 is the number of encoded nibbles */
- data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);
-
- evbuffer_add(evbuf, data, (off + 1) / 2);
-}
-
-/*
- * Support variable length encoding of tags; we use the high bit in each
- * octet as a continuation signal.
- */
-
-int
-evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
-{
- int bytes = 0;
- ev_uint8_t data[5];
-
- memset(data, 0, sizeof(data));
- do {
- ev_uint8_t lower = tag & 0x7f;
- tag >>= 7;
-
- if (tag)
- lower |= 0x80;
-
- data[bytes++] = lower;
- } while (tag);
-
- if (evbuf != NULL)
- evbuffer_add(evbuf, data, bytes);
-
- return (bytes);
-}
-
-static int
-decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
-{
- ev_uint32_t number = 0;
- ev_uint8_t *data = EVBUFFER_DATA(evbuf);
- int len = EVBUFFER_LENGTH(evbuf);
- int count = 0, shift = 0, done = 0;
-
- while (count++ < len) {
- ev_uint8_t lower = *data++;
- number |= (lower & 0x7f) << shift;
- shift += 7;
-
- if (!(lower & 0x80)) {
- done = 1;
- break;
- }
- }
-
- if (!done)
- return (-1);
-
- if (dodrain)
- evbuffer_drain(evbuf, count);
-
- if (ptag != NULL)
- *ptag = number;
-
- return (count);
-}
-
-int
-evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
-{
- return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
-}
-
-/*
- * Marshal a data type, the general format is as follows:
- *
- * tag number: one byte; length: var bytes; payload: var bytes
- */
-
-void
-evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
- const void *data, ev_uint32_t len)
-{
- evtag_encode_tag(evbuf, tag);
- encode_int(evbuf, len);
- evbuffer_add(evbuf, (void *)data, len);
-}
-
-/* Marshaling for integers */
-void
-evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
-{
- evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
- encode_int(_buf, integer);
-
- evtag_encode_tag(evbuf, tag);
- encode_int(evbuf, EVBUFFER_LENGTH(_buf));
- evbuffer_add_buffer(evbuf, _buf);
-}
-
-void
-evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
-{
- evtag_marshal(buf, tag, string, strlen(string));
-}
-
-void
-evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
-{
- evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
-
- encode_int(_buf, tv->tv_sec);
- encode_int(_buf, tv->tv_usec);
-
- evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf),
- EVBUFFER_LENGTH(_buf));
-}
-
-static int
-decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
-{
- ev_uint32_t number = 0;
- ev_uint8_t *data = EVBUFFER_DATA(evbuf);
- int len = EVBUFFER_LENGTH(evbuf);
- int nibbles = 0;
-
- if (!len)
- return (-1);
-
- nibbles = ((data[0] & 0xf0) >> 4) + 1;
- if (nibbles > 8 || (nibbles >> 1) + 1 > len)
- return (-1);
- len = (nibbles >> 1) + 1;
-
- while (nibbles > 0) {
- number <<= 4;
- if (nibbles & 0x1)
- number |= data[nibbles >> 1] & 0x0f;
- else
- number |= (data[nibbles >> 1] & 0xf0) >> 4;
- nibbles--;
- }
-
- if (dodrain)
- evbuffer_drain(evbuf, len);
-
- *pnumber = number;
-
- return (len);
-}
-
-int
-evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
-{
- return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
-}
-
-int
-evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
-{
- return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
-}
-
-int
-evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
-{
- struct evbuffer tmp;
- int res, len;
-
- len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
- if (len == -1)
- return (-1);
-
- tmp = *evbuf;
- tmp.buffer += len;
- tmp.off -= len;
-
- res = decode_int_internal(plength, &tmp, 0);
- if (res == -1)
- return (-1);
-
- *plength += res + len;
-
- return (0);
-}
-
-int
-evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
-{
- struct evbuffer tmp;
- int res, len;
-
- len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
- if (len == -1)
- return (-1);
-
- tmp = *evbuf;
- tmp.buffer += len;
- tmp.off -= len;
-
- res = decode_int_internal(plength, &tmp, 0);
- if (res == -1)
- return (-1);
-
- return (0);
-}
-
-int
-evtag_consume(struct evbuffer *evbuf)
-{
- ev_uint32_t len;
- if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
- return (-1);
- if (evtag_decode_int(&len, evbuf) == -1)
- return (-1);
- evbuffer_drain(evbuf, len);
-
- return (0);
-}
-
-/* Reads the data type from an event buffer */
-
-int
-evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
-{
- ev_uint32_t len;
- ev_uint32_t integer;
-
- if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
- return (-1);
- if (evtag_decode_int(&integer, src) == -1)
- return (-1);
- len = integer;
-
- if (EVBUFFER_LENGTH(src) < len)
- return (-1);
-
- if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1)
- return (-1);
-
- evbuffer_drain(src, len);
-
- return (len);
-}
-
-/* Marshaling for integers */
-
-int
-evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
- ev_uint32_t *pinteger)
-{
- ev_uint32_t tag;
- ev_uint32_t len;
- ev_uint32_t integer;
-
- if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
- return (-1);
- if (need_tag != tag)
- return (-1);
- if (evtag_decode_int(&integer, evbuf) == -1)
- return (-1);
- len = integer;
-
- if (EVBUFFER_LENGTH(evbuf) < len)
- return (-1);
-
- evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
- if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1)
- return (-1);
-
- evbuffer_drain(evbuf, len);
-
- return (evtag_decode_int(pinteger, _buf));
-}
-
-/* Unmarshal a fixed length tag */
-
-int
-evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
- size_t len)
-{
- ev_uint32_t tag;
-
- /* Initialize this event buffer so that we can read into it */
- evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
-
- /* Now unmarshal a tag and check that it matches the tag we want */
- if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag)
- return (-1);
-
- if (EVBUFFER_LENGTH(_buf) != len)
- return (-1);
-
- memcpy(data, EVBUFFER_DATA(_buf), len);
- return (0);
-}
-
-int
-evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
- char **pstring)
-{
- ev_uint32_t tag;
-
- evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
-
- if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
- return (-1);
-
- *pstring = calloc(EVBUFFER_LENGTH(_buf) + 1, 1);
- if (*pstring == NULL)
- event_err(1, "%s: calloc", __func__);
- evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf));
-
- return (0);
-}
-
-int
-evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
- struct timeval *ptv)
-{
- ev_uint32_t tag;
- ev_uint32_t integer;
-
- evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
- if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
- return (-1);
-
- if (evtag_decode_int(&integer, _buf) == -1)
- return (-1);
- ptv->tv_sec = integer;
- if (evtag_decode_int(&integer, _buf) == -1)
- return (-1);
- ptv->tv_usec = integer;
-
- return (0);
-}
diff --git a/lib/libevent/evhttp.h b/lib/libevent/evhttp.h
deleted file mode 100644
index 266a1952dbc..00000000000
--- a/lib/libevent/evhttp.h
+++ /dev/null
@@ -1,365 +0,0 @@
-/* $NetBSD: evhttp.h,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVHTTP_H_
-#define _EVHTTP_H_
-
-#include <event.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** @file evhttp.h
- *
- * Basic support for HTTP serving.
- *
- * As libevent is a library for dealing with event notification and most
- * interesting applications are networked today, I have often found the
- * need to write HTTP code. The following prototypes and definitions provide
- * an application with a minimal interface for making HTTP requests and for
- * creating a very simple HTTP server.
- */
-
-/* Response codes */
-#define HTTP_OK 200
-#define HTTP_NOCONTENT 204
-#define HTTP_MOVEPERM 301
-#define HTTP_MOVETEMP 302
-#define HTTP_NOTMODIFIED 304
-#define HTTP_BADREQUEST 400
-#define HTTP_NOTFOUND 404
-#define HTTP_SERVUNAVAIL 503
-
-struct evhttp;
-struct evhttp_request;
-struct evkeyvalq;
-
-/** Create a new HTTP server
- *
- * @param base (optional) the event base to receive the HTTP events
- * @return a pointer to a newly initialized evhttp server structure
- */
-struct evhttp *evhttp_new(struct event_base *base);
-
-/**
- * Binds an HTTP server on the specified address and port.
- *
- * Can be called multiple times to bind the same http server
- * to multiple different ports.
- *
- * @param http a pointer to an evhttp object
- * @param address a string containing the IP address to listen(2) on
- * @param port the port number to listen on
- * @return a newly allocated evhttp struct
- * @see evhttp_free()
- */
-int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
-
-/**
- * Makes an HTTP server accept connections on the specified socket
- *
- * This may be useful to create a socket and then fork multiple instances
- * of an http server, or when a socket has been communicated via file
- * descriptor passing in situations where an http servers does not have
- * permissions to bind to a low-numbered port.
- *
- * Can be called multiple times to have the http server listen to
- * multiple different sockets.
- *
- * @param http a pointer to an evhttp object
- * @param fd a socket fd that is ready for accepting connections
- * @return 0 on success, -1 on failure.
- * @see evhttp_free(), evhttp_bind_socket()
- */
-int evhttp_accept_socket(struct evhttp *http, int fd);
-
-/**
- * Free the previously created HTTP server.
- *
- * Works only if no requests are currently being served.
- *
- * @param http the evhttp server object to be freed
- * @see evhttp_start()
- */
-void evhttp_free(struct evhttp* http);
-
-/** Set a callback for a specified URI */
-void evhttp_set_cb(struct evhttp *, const char *,
- void (*)(struct evhttp_request *, void *), void *);
-
-/** Removes the callback for a specified URI */
-int evhttp_del_cb(struct evhttp *, const char *);
-
-/** Set a callback for all requests that are not caught by specific callbacks
- */
-void evhttp_set_gencb(struct evhttp *,
- void (*)(struct evhttp_request *, void *), void *);
-
-/**
- * Set the timeout for an HTTP request.
- *
- * @param http an evhttp object
- * @param timeout_in_secs the timeout, in seconds
- */
-void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
-
-/* Request/Response functionality */
-
-/**
- * Send an HTML error message to the client.
- *
- * @param req a request object
- * @param error the HTTP error code
- * @param reason a brief explanation of the error
- */
-void evhttp_send_error(struct evhttp_request *req, int error,
- const char *reason);
-
-/**
- * Send an HTML reply to the client.
- *
- * @param req a request object
- * @param code the HTTP response code to send
- * @param reason a brief message to send with the response code
- * @param databuf the body of the response
- */
-void evhttp_send_reply(struct evhttp_request *req, int code,
- const char *reason, struct evbuffer *databuf);
-
-/* Low-level response interface, for streaming/chunked replies */
-void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
-void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
-void evhttp_send_reply_end(struct evhttp_request *);
-
-/**
- * Start an HTTP server on the specified address and port
- *
- * DEPRECATED: it does not allow an event base to be specified
- *
- * @param address the address to which the HTTP server should be bound
- * @param port the port number on which the HTTP server should listen
- * @return an struct evhttp object
- */
-struct evhttp *evhttp_start(const char *address, u_short port);
-
-/*
- * Interfaces for making requests
- */
-enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
-
-enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
-
-/**
- * the request structure that a server receives.
- * WARNING: expect this structure to change. I will try to provide
- * reasonable accessors.
- */
-struct evhttp_request {
-#if defined(TAILQ_ENTRY)
- TAILQ_ENTRY(evhttp_request) next;
-#else
-struct {
- struct evhttp_request *tqe_next;
- struct evhttp_request **tqe_prev;
-} next;
-#endif
-
- /* the connection object that this request belongs to */
- struct evhttp_connection *evcon;
- int flags;
-#define EVHTTP_REQ_OWN_CONNECTION 0x0001
-#define EVHTTP_PROXY_REQUEST 0x0002
-
- struct evkeyvalq *input_headers;
- struct evkeyvalq *output_headers;
-
- /* address of the remote host and the port connection came from */
- char *remote_host;
- u_short remote_port;
-
- enum evhttp_request_kind kind;
- enum evhttp_cmd_type type;
-
- char *uri; /* uri after HTTP request was parsed */
-
- char major; /* HTTP Major number */
- char minor; /* HTTP Minor number */
-
- int response_code; /* HTTP Response code */
- char *response_code_line; /* Readable response */
-
- struct evbuffer *input_buffer; /* read data */
- ev_int64_t ntoread;
- int chunked;
-
- struct evbuffer *output_buffer; /* outgoing post or data */
-
- /* Callback */
- void (*cb)(struct evhttp_request *, void *);
- void *cb_arg;
-
- /*
- * Chunked data callback - call for each completed chunk if
- * specified. If not specified, all the data is delivered via
- * the regular callback.
- */
- void (*chunk_cb)(struct evhttp_request *, void *);
-};
-
-/**
- * Creates a new request object that needs to be filled in with the request
- * parameters. The callback is executed when the request completed or an
- * error occurred.
- */
-struct evhttp_request *evhttp_request_new(
- void (*cb)(struct evhttp_request *, void *), void *arg);
-
-/** enable delivery of chunks to requestor */
-void evhttp_request_set_chunked_cb(struct evhttp_request *,
- void (*cb)(struct evhttp_request *, void *));
-
-/** Frees the request object and removes associated events. */
-void evhttp_request_free(struct evhttp_request *req);
-
-/**
- * A connection object that can be used to for making HTTP requests. The
- * connection object tries to establish the connection when it is given an
- * http request object.
- */
-struct evhttp_connection *evhttp_connection_new(
- const char *address, unsigned short port);
-
-/** Frees an http connection */
-void evhttp_connection_free(struct evhttp_connection *evcon);
-
-/** sets the ip address from which http connections are made */
-void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
- const char *address);
-
-/** sets the local port from which http connections are made */
-void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
- unsigned short port);
-
-/** Sets the timeout for events related to this connection */
-void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
- int timeout_in_secs);
-
-/** Sets the retry limit for this connection - -1 repeats indefnitely */
-void evhttp_connection_set_retries(struct evhttp_connection *evcon,
- int retry_max);
-
-/** Set a callback for connection close. */
-void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
- void (*)(struct evhttp_connection *, void *), void *);
-
-/**
- * Associates an event base with the connection - can only be called
- * on a freshly created connection object that has not been used yet.
- */
-void evhttp_connection_set_base(struct evhttp_connection *evcon,
- struct event_base *base);
-
-/** Get the remote address and port associated with this connection. */
-void evhttp_connection_get_peer(struct evhttp_connection *evcon,
- char **address, u_short *port);
-
-/** The connection gets ownership of the request */
-int evhttp_make_request(struct evhttp_connection *evcon,
- struct evhttp_request *req,
- enum evhttp_cmd_type type, const char *uri);
-
-const char *evhttp_request_uri(struct evhttp_request *req);
-
-/* Interfaces for dealing with HTTP headers */
-
-const char *evhttp_find_header(const struct evkeyvalq *, const char *);
-int evhttp_remove_header(struct evkeyvalq *, const char *);
-int evhttp_add_header(struct evkeyvalq *, const char *, const char *);
-void evhttp_clear_headers(struct evkeyvalq *);
-
-/* Miscellaneous utility functions */
-
-
-/**
- Helper function to encode a URI.
-
- The returned string must be freed by the caller.
-
- @param uri an unencoded URI
- @return a newly allocated URI-encoded string
- */
-char *evhttp_encode_uri(const char *uri);
-
-
-/**
- Helper function to decode a URI.
-
- The returned string must be freed by the caller.
-
- @param uri an encoded URI
- @return a newly allocated unencoded URI
- */
-char *evhttp_decode_uri(const char *uri);
-
-
-/**
- * Helper function to parse out arguments in a query.
- *
- * Parsing a uri like
- *
- * http://foo.com/?q=test&s=some+thing
- *
- * will result in two entries in the key value queue.
-
- * The first entry is: key="q", value="test"
- * The second entry is: key="s", value="some thing"
- *
- * @param uri the request URI
- * @param headers the head of the evkeyval queue
- */
-void evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
-
-
-/**
- * Escape HTML character entities in a string.
- *
- * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
- * &#039; and &amp; correspondingly.
- *
- * The returned string needs to be freed by the caller.
- *
- * @param html an unescaped HTML string
- * @return an escaped HTML string
- */
-char *evhttp_htmlescape(const char *html);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _EVHTTP_H_ */
diff --git a/lib/libevent/evrpc-internal.h b/lib/libevent/evrpc-internal.h
deleted file mode 100644
index 6f89b4b5c18..00000000000
--- a/lib/libevent/evrpc-internal.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* $NetBSD: evrpc-internal.h,v 1.1 2008/05/16 20:24:58 peter Exp $ */
-/*
- * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVRPC_INTERNAL_H_
-#define _EVRPC_INTERNAL_H_
-
-#include "http-internal.h"
-
-struct evrpc;
-
-#define EVRPC_URI_PREFIX "/.rpc."
-
-struct evrpc_hook {
- TAILQ_ENTRY(evrpc_hook) (next);
-
- /* returns -1; if the rpc should be aborted, is allowed to rewrite */
- int (*process)(struct evhttp_request *, struct evbuffer *, void *);
- void *process_arg;
-};
-
-TAILQ_HEAD(evrpc_hook_list, evrpc_hook);
-
-/*
- * this is shared between the base and the pool, so that we can reuse
- * the hook adding functions; we alias both evrpc_pool and evrpc_base
- * to this common structure.
- */
-struct _evrpc_hooks {
- /* hooks for processing outbound and inbound rpcs */
- struct evrpc_hook_list in_hooks;
- struct evrpc_hook_list out_hooks;
-};
-
-#define input_hooks common.in_hooks
-#define output_hooks common.out_hooks
-
-struct evrpc_base {
- struct _evrpc_hooks common;
-
- /* the HTTP server under which we register our RPC calls */
- struct evhttp* http_server;
-
- /* a list of all RPCs registered with us */
- TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs;
-};
-
-struct evrpc_req_generic;
-void evrpc_reqstate_free(struct evrpc_req_generic* rpc_state);
-
-/* A pool for holding evhttp_connection objects */
-struct evrpc_pool {
- struct _evrpc_hooks common;
-
- struct event_base *base;
-
- struct evconq connections;
-
- int timeout;
-
- TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) requests;
-};
-
-
-#endif /* _EVRPC_INTERNAL_H_ */
diff --git a/lib/libevent/evrpc.c b/lib/libevent/evrpc.c
deleted file mode 100644
index ffad284d09b..00000000000
--- a/lib/libevent/evrpc.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/* $NetBSD: evrpc.c,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <sys/queue.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <assert.h>
-
-#include "event.h"
-#include "evrpc.h"
-#include "evrpc-internal.h"
-#include "evhttp.h"
-#include "evutil.h"
-#include "log.h"
-
-struct evrpc_base *
-evrpc_init(struct evhttp *http_server)
-{
- struct evrpc_base* base = calloc(1, sizeof(struct evrpc_base));
- if (base == NULL)
- return (NULL);
-
- /* we rely on the tagging sub system */
- evtag_init();
-
- TAILQ_INIT(&base->registered_rpcs);
- TAILQ_INIT(&base->input_hooks);
- TAILQ_INIT(&base->output_hooks);
- base->http_server = http_server;
-
- return (base);
-}
-
-void
-evrpc_free(struct evrpc_base *base)
-{
- struct evrpc *rpc;
- struct evrpc_hook *hook;
-
- while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
- assert(evrpc_unregister_rpc(base, rpc->uri));
- }
- while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
- assert(evrpc_remove_hook(base, EVRPC_INPUT, hook));
- }
- while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
- assert(evrpc_remove_hook(base, EVRPC_OUTPUT, hook));
- }
- free(base);
-}
-
-void *
-evrpc_add_hook(void *vbase,
- enum EVRPC_HOOK_TYPE hook_type,
- int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
- void *cb_arg)
-{
- struct _evrpc_hooks *base = vbase;
- struct evrpc_hook_list *head = NULL;
- struct evrpc_hook *hook = NULL;
- switch (hook_type) {
- case EVRPC_INPUT:
- head = &base->in_hooks;
- break;
- case EVRPC_OUTPUT:
- head = &base->out_hooks;
- break;
- default:
- assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
- }
-
- hook = calloc(1, sizeof(struct evrpc_hook));
- assert(hook != NULL);
-
- hook->process = cb;
- hook->process_arg = cb_arg;
- TAILQ_INSERT_TAIL(head, hook, next);
-
- return (hook);
-}
-
-static int
-evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
-{
- struct evrpc_hook *hook = NULL;
- TAILQ_FOREACH(hook, head, next) {
- if (hook == handle) {
- TAILQ_REMOVE(head, hook, next);
- free(hook);
- return (1);
- }
- }
-
- return (0);
-}
-
-/*
- * remove the hook specified by the handle
- */
-
-int
-evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
-{
- struct _evrpc_hooks *base = vbase;
- struct evrpc_hook_list *head = NULL;
- switch (hook_type) {
- case EVRPC_INPUT:
- head = &base->in_hooks;
- break;
- case EVRPC_OUTPUT:
- head = &base->out_hooks;
- break;
- default:
- assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
- }
-
- return (evrpc_remove_hook_internal(head, handle));
-}
-
-static int
-evrpc_process_hooks(struct evrpc_hook_list *head,
- struct evhttp_request *req, struct evbuffer *evbuf)
-{
- struct evrpc_hook *hook;
- TAILQ_FOREACH(hook, head, next) {
- if (hook->process(req, evbuf, hook->process_arg) == -1)
- return (-1);
- }
-
- return (0);
-}
-
-static void evrpc_pool_schedule(struct evrpc_pool *pool);
-static void evrpc_request_cb(struct evhttp_request *, void *);
-void evrpc_request_done(struct evrpc_req_generic*);
-
-/*
- * Registers a new RPC with the HTTP server. The evrpc object is expected
- * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
- * calls this function.
- */
-
-static char *
-evrpc_construct_uri(const char *uri)
-{
- char *constructed_uri;
- int constructed_uri_len;
-
- constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
- if ((constructed_uri = malloc(constructed_uri_len)) == NULL)
- event_err(1, "%s: failed to register rpc at %s",
- __func__, uri);
- memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
- memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
- constructed_uri[constructed_uri_len - 1] = '\0';
-
- return (constructed_uri);
-}
-
-int
-evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
- void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
-{
- char *constructed_uri = evrpc_construct_uri(rpc->uri);
-
- rpc->base = base;
- rpc->cb = cb;
- rpc->cb_arg = cb_arg;
-
- TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
-
- evhttp_set_cb(base->http_server,
- constructed_uri,
- evrpc_request_cb,
- rpc);
-
- free(constructed_uri);
-
- return (0);
-}
-
-int
-evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
-{
- char *registered_uri = NULL;
- struct evrpc *rpc;
-
- /* find the right rpc; linear search might be slow */
- TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
- if (strcmp(rpc->uri, name) == 0)
- break;
- }
- if (rpc == NULL) {
- /* We did not find an RPC with this name */
- return (-1);
- }
- TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
-
- free((char *)rpc->uri);
- free(rpc);
-
- registered_uri = evrpc_construct_uri(name);
-
- /* remove the http server callback */
- assert(evhttp_del_cb(base->http_server, registered_uri) == 0);
-
- free(registered_uri);
- return (0);
-}
-
-static void
-evrpc_request_cb(struct evhttp_request *req, void *arg)
-{
- struct evrpc *rpc = arg;
- struct evrpc_req_generic *rpc_state = NULL;
-
- /* let's verify the outside parameters */
- if (req->type != EVHTTP_REQ_POST ||
- EVBUFFER_LENGTH(req->input_buffer) <= 0)
- goto error;
-
- /*
- * we might want to allow hooks to suspend the processing,
- * but at the moment, we assume that they just act as simple
- * filters.
- */
- if (evrpc_process_hooks(&rpc->base->input_hooks,
- req, req->input_buffer) == -1)
- goto error;
-
- rpc_state = calloc(1, sizeof(struct evrpc_req_generic));
- if (rpc_state == NULL)
- goto error;
-
- /* let's check that we can parse the request */
- rpc_state->request = rpc->request_new();
- if (rpc_state->request == NULL)
- goto error;
-
- rpc_state->rpc = rpc;
-
- if (rpc->request_unmarshal(
- rpc_state->request, req->input_buffer) == -1) {
- /* we failed to parse the request; that's a bummer */
- goto error;
- }
-
- /* at this point, we have a well formed request, prepare the reply */
-
- rpc_state->reply = rpc->reply_new();
- if (rpc_state->reply == NULL)
- goto error;
-
- rpc_state->http_req = req;
- rpc_state->done = evrpc_request_done;
-
- /* give the rpc to the user; they can deal with it */
- rpc->cb(rpc_state, rpc->cb_arg);
-
- return;
-
-error:
- evrpc_reqstate_free(rpc_state);
- evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
- return;
-}
-
-void
-evrpc_reqstate_free(struct evrpc_req_generic* rpc_state)
-{
- /* clean up all memory */
- if (rpc_state != NULL) {
- struct evrpc *rpc = rpc_state->rpc;
-
- if (rpc_state->request != NULL)
- rpc->request_free(rpc_state->request);
- if (rpc_state->reply != NULL)
- rpc->reply_free(rpc_state->reply);
- free(rpc_state);
- }
-}
-
-void
-evrpc_request_done(struct evrpc_req_generic* rpc_state)
-{
- struct evhttp_request *req = rpc_state->http_req;
- struct evrpc *rpc = rpc_state->rpc;
- struct evbuffer* data = NULL;
-
- if (rpc->reply_complete(rpc_state->reply) == -1) {
- /* the reply was not completely filled in. error out */
- goto error;
- }
-
- if ((data = evbuffer_new()) == NULL) {
- /* out of memory */
- goto error;
- }
-
- /* serialize the reply */
- rpc->reply_marshal(data, rpc_state->reply);
-
- /* do hook based tweaks to the request */
- if (evrpc_process_hooks(&rpc->base->output_hooks,
- req, data) == -1)
- goto error;
-
- /* on success, we are going to transmit marshaled binary data */
- if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
- evhttp_add_header(req->output_headers,
- "Content-Type", "application/octet-stream");
- }
-
- evhttp_send_reply(req, HTTP_OK, "OK", data);
-
- evbuffer_free(data);
-
- evrpc_reqstate_free(rpc_state);
-
- return;
-
-error:
- if (data != NULL)
- evbuffer_free(data);
- evrpc_reqstate_free(rpc_state);
- evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
- return;
-}
-
-/* Client implementation of RPC site */
-
-static int evrpc_schedule_request(struct evhttp_connection *connection,
- struct evrpc_request_wrapper *ctx);
-
-struct evrpc_pool *
-evrpc_pool_new(struct event_base *base)
-{
- struct evrpc_pool *pool = calloc(1, sizeof(struct evrpc_pool));
- if (pool == NULL)
- return (NULL);
-
- TAILQ_INIT(&pool->connections);
- TAILQ_INIT(&pool->requests);
-
- TAILQ_INIT(&pool->input_hooks);
- TAILQ_INIT(&pool->output_hooks);
-
- pool->base = base;
- pool->timeout = -1;
-
- return (pool);
-}
-
-static void
-evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
-{
- free(request->name);
- free(request);
-}
-
-void
-evrpc_pool_free(struct evrpc_pool *pool)
-{
- struct evhttp_connection *connection;
- struct evrpc_request_wrapper *request;
- struct evrpc_hook *hook;
-
- while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
- TAILQ_REMOVE(&pool->requests, request, next);
- /* if this gets more complicated we need our own function */
- evrpc_request_wrapper_free(request);
- }
-
- while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
- TAILQ_REMOVE(&pool->connections, connection, next);
- evhttp_connection_free(connection);
- }
-
- while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
- assert(evrpc_remove_hook(pool, EVRPC_INPUT, hook));
- }
-
- while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
- assert(evrpc_remove_hook(pool, EVRPC_OUTPUT, hook));
- }
-
- free(pool);
-}
-
-/*
- * Add a connection to the RPC pool. A request scheduled on the pool
- * may use any available connection.
- */
-
-void
-evrpc_pool_add_connection(struct evrpc_pool *pool,
- struct evhttp_connection *connection) {
- assert(connection->http_server == NULL);
- TAILQ_INSERT_TAIL(&pool->connections, connection, next);
-
- /*
- * associate an event base with this connection
- */
- if (pool->base != NULL)
- evhttp_connection_set_base(connection, pool->base);
-
- /*
- * unless a timeout was specifically set for a connection,
- * the connection inherits the timeout from the pool.
- */
- if (connection->timeout == -1)
- connection->timeout = pool->timeout;
-
- /*
- * if we have any requests pending, schedule them with the new
- * connections.
- */
-
- if (TAILQ_FIRST(&pool->requests) != NULL) {
- struct evrpc_request_wrapper *request =
- TAILQ_FIRST(&pool->requests);
- TAILQ_REMOVE(&pool->requests, request, next);
- evrpc_schedule_request(connection, request);
- }
-}
-
-void
-evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
-{
- struct evhttp_connection *evcon;
- TAILQ_FOREACH(evcon, &pool->connections, next) {
- evcon->timeout = timeout_in_secs;
- }
- pool->timeout = timeout_in_secs;
-}
-
-
-static void evrpc_reply_done(struct evhttp_request *, void *);
-static void evrpc_request_timeout(int, short, void *);
-
-/*
- * Finds a connection object associated with the pool that is currently
- * idle and can be used to make a request.
- */
-static struct evhttp_connection *
-evrpc_pool_find_connection(struct evrpc_pool *pool)
-{
- struct evhttp_connection *connection;
- TAILQ_FOREACH(connection, &pool->connections, next) {
- if (TAILQ_FIRST(&connection->requests) == NULL)
- return (connection);
- }
-
- return (NULL);
-}
-
-/*
- * We assume that the ctx is no longer queued on the pool.
- */
-static int
-evrpc_schedule_request(struct evhttp_connection *connection,
- struct evrpc_request_wrapper *ctx)
-{
- struct evhttp_request *req = NULL;
- struct evrpc_pool *pool = ctx->pool;
- struct evrpc_status status;
- char *uri = NULL;
- int res = 0;
-
- if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
- goto error;
-
- /* serialize the request data into the output buffer */
- ctx->request_marshal(req->output_buffer, ctx->request);
-
- uri = evrpc_construct_uri(ctx->name);
- if (uri == NULL)
- goto error;
-
- /* we need to know the connection that we might have to abort */
- ctx->evcon = connection;
-
- /* apply hooks to the outgoing request */
- if (evrpc_process_hooks(&pool->output_hooks,
- req, req->output_buffer) == -1)
- goto error;
-
- if (pool->timeout > 0) {
- /*
- * a timeout after which the whole rpc is going to be aborted.
- */
- struct timeval tv;
- evutil_timerclear(&tv);
- tv.tv_sec = pool->timeout;
- evtimer_add(&ctx->ev_timeout, &tv);
- }
-
- /* start the request over the connection */
- res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
- free(uri);
-
- if (res == -1)
- goto error;
-
- return (0);
-
-error:
- memset(&status, 0, sizeof(status));
- status.error = EVRPC_STATUS_ERR_UNSTARTED;
- (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
- evrpc_request_wrapper_free(ctx);
- return (-1);
-}
-
-int
-evrpc_make_request(struct evrpc_request_wrapper *ctx)
-{
- struct evrpc_pool *pool = ctx->pool;
-
- /* initialize the event structure for this rpc */
- evtimer_set(&ctx->ev_timeout, evrpc_request_timeout, ctx);
- if (pool->base != NULL)
- event_base_set(pool->base, &ctx->ev_timeout);
-
- /* we better have some available connections on the pool */
- assert(TAILQ_FIRST(&pool->connections) != NULL);
-
- /*
- * if no connection is available, we queue the request on the pool,
- * the next time a connection is empty, the rpc will be send on that.
- */
- TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
-
- evrpc_pool_schedule(pool);
-
- return (0);
-}
-
-static void
-evrpc_reply_done(struct evhttp_request *req, void *arg)
-{
- struct evrpc_request_wrapper *ctx = arg;
- struct evrpc_pool *pool = ctx->pool;
- struct evrpc_status status;
- int res = -1;
-
- /* cancel any timeout we might have scheduled */
- event_del(&ctx->ev_timeout);
-
- memset(&status, 0, sizeof(status));
- status.http_req = req;
-
- /* we need to get the reply now */
- if (req != NULL) {
- /* apply hooks to the incoming request */
- if (evrpc_process_hooks(&pool->input_hooks,
- req, req->input_buffer) == -1) {
- status.error = EVRPC_STATUS_ERR_HOOKABORTED;
- res = -1;
- } else {
- res = ctx->reply_unmarshal(ctx->reply,
- req->input_buffer);
- if (res == -1) {
- status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
- }
- }
- } else {
- status.error = EVRPC_STATUS_ERR_TIMEOUT;
- }
-
- if (res == -1) {
- /* clear everything that we might have written previously */
- ctx->reply_clear(ctx->reply);
- }
-
- (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
-
- evrpc_request_wrapper_free(ctx);
-
- /* the http layer owns the request structure */
-
- /* see if we can schedule another request */
- evrpc_pool_schedule(pool);
-}
-
-static void
-evrpc_pool_schedule(struct evrpc_pool *pool)
-{
- struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
- struct evhttp_connection *evcon;
-
- /* if no requests are pending, we have no work */
- if (ctx == NULL)
- return;
-
- if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
- TAILQ_REMOVE(&pool->requests, ctx, next);
- evrpc_schedule_request(evcon, ctx);
- }
-}
-
-static void
-evrpc_request_timeout(int fd, short what, void *arg)
-{
- struct evrpc_request_wrapper *ctx = arg;
- struct evhttp_connection *evcon = ctx->evcon;
- assert(evcon != NULL);
-
- evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
-}
diff --git a/lib/libevent/evrpc.h b/lib/libevent/evrpc.h
deleted file mode 100644
index fa3eee61973..00000000000
--- a/lib/libevent/evrpc.h
+++ /dev/null
@@ -1,487 +0,0 @@
-/* $NetBSD: evrpc.h,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVRPC_H_
-#define _EVRPC_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** @file evrpc.h
- *
- * This header files provides basic support for an RPC server and client.
- *
- * To support RPCs in a server, every supported RPC command needs to be
- * defined and registered.
- *
- * EVRPC_HEADER(SendCommand, Request, Reply);
- *
- * SendCommand is the name of the RPC command.
- * Request is the name of a structure generated by event_rpcgen.py.
- * It contains all parameters relating to the SendCommand RPC. The
- * server needs to fill in the Reply structure.
- * Reply is the name of a structure generated by event_rpcgen.py. It
- * contains the answer to the RPC.
- *
- * To register an RPC with an HTTP server, you need to first create an RPC
- * base with:
- *
- * struct evrpc_base *base = evrpc_init(http);
- *
- * A specific RPC can then be registered with
- *
- * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg);
- *
- * when the server receives an appropriately formatted RPC, the user callback
- * is invokved. The callback needs to fill in the reply structure.
- *
- * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
- *
- * To send the reply, call EVRPC_REQUEST_DONE(rpc);
- *
- * See the regression test for an example.
- */
-
-struct evbuffer;
-struct event_base;
-struct evrpc_req_generic;
-
-/* Encapsulates a request */
-struct evrpc {
- TAILQ_ENTRY(evrpc) next;
-
- /* the URI at which the request handler lives */
- const char* uri;
-
- /* creates a new request structure */
- void *(*request_new)(void);
-
- /* frees the request structure */
- void (*request_free)(void *);
-
- /* unmarshals the buffer into the proper request structure */
- int (*request_unmarshal)(void *, struct evbuffer *);
-
- /* creates a new reply structure */
- void *(*reply_new)(void);
-
- /* creates a new reply structure */
- void (*reply_free)(void *);
-
- /* verifies that the reply is valid */
- int (*reply_complete)(void *);
-
- /* marshals the reply into a buffer */
- void (*reply_marshal)(struct evbuffer*, void *);
-
- /* the callback invoked for each received rpc */
- void (*cb)(struct evrpc_req_generic *, void *);
- void *cb_arg;
-
- /* reference for further configuration */
- struct evrpc_base *base;
-};
-
-/** The type of a specific RPC Message
- *
- * @param rpcname the name of the RPC message
- */
-#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
-
-struct evhttp_request;
-struct evrpc_status;
-
-/* We alias the RPC specific structs to this voided one */
-struct evrpc_req_generic {
- /* the unmarshaled request object */
- void *request;
-
- /* the empty reply object that needs to be filled in */
- void *reply;
-
- /*
- * the static structure for this rpc; that can be used to
- * automatically unmarshal and marshal the http buffers.
- */
- struct evrpc *rpc;
-
- /*
- * the http request structure on which we need to answer.
- */
- struct evhttp_request* http_req;
-
- /*
- * callback to reply and finish answering this rpc
- */
- void (*done)(struct evrpc_req_generic* rpc);
-};
-
-/** Creates the definitions and prototypes for an RPC
- *
- * You need to use EVRPC_HEADER to create structures and function prototypes
- * needed by the server and client implementation. The structures have to be
- * defined in an .rpc file and converted to source code via event_rpcgen.py
- *
- * @param rpcname the name of the RPC
- * @param reqstruct the name of the RPC request structure
- * @param replystruct the name of the RPC reply structure
- * @see EVRPC_GENERATE()
- */
-#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
-EVRPC_STRUCT(rpcname) { \
- struct reqstruct* request; \
- struct rplystruct* reply; \
- struct evrpc* rpc; \
- struct evhttp_request* http_req; \
- void (*done)(struct evrpc_status *, \
- struct evrpc* rpc, void *request, void *reply); \
-}; \
-int evrpc_send_request_##rpcname(struct evrpc_pool *, \
- struct reqstruct *, struct rplystruct *, \
- void (*)(struct evrpc_status *, \
- struct reqstruct *, struct rplystruct *, void *cbarg), \
- void *);
-
-/** Generates the code for receiving and sending an RPC message
- *
- * EVRPC_GENERATE is used to create the code corresponding to sending
- * and receiving a particular RPC message
- *
- * @param rpcname the name of the RPC
- * @param reqstruct the name of the RPC request structure
- * @param replystruct the name of the RPC reply structure
- * @see EVRPC_HEADER()
- */
-#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
-int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
- struct reqstruct *request, struct rplystruct *reply, \
- void (*cb)(struct evrpc_status *, \
- struct reqstruct *, struct rplystruct *, void *cbarg), \
- void *cbarg) { \
- struct evrpc_status status; \
- struct evrpc_request_wrapper *ctx; \
- ctx = (struct evrpc_request_wrapper *) \
- malloc(sizeof(struct evrpc_request_wrapper)); \
- if (ctx == NULL) \
- goto error; \
- ctx->pool = pool; \
- ctx->evcon = NULL; \
- ctx->name = strdup(#rpcname); \
- if (ctx->name == NULL) { \
- free(ctx); \
- goto error; \
- } \
- ctx->cb = (void (*)(struct evrpc_status *, \
- void *, void *, void *))cb; \
- ctx->cb_arg = cbarg; \
- ctx->request = (void *)request; \
- ctx->reply = (void *)reply; \
- ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \
- ctx->reply_clear = (void (*)(void *))rplystruct##_clear; \
- ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \
- return (evrpc_make_request(ctx)); \
-error: \
- memset(&status, 0, sizeof(status)); \
- status.error = EVRPC_STATUS_ERR_UNSTARTED; \
- (*(cb))(&status, request, reply, cbarg); \
- return (-1); \
-}
-
-/** Provides access to the HTTP request object underlying an RPC
- *
- * Access to the underlying http object; can be used to look at headers or
- * for getting the remote ip address
- *
- * @param rpc_req the rpc request structure provided to the server callback
- * @return an struct evhttp_request object that can be inspected for
- * HTTP headers or sender information.
- */
-#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
-
-/** Creates the reply to an RPC request
- *
- * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
- * to have been filled in. The request and reply pointers become invalid
- * after this call has finished.
- *
- * @param rpc_req the rpc request structure provided to the server callback
- */
-#define EVRPC_REQUEST_DONE(rpc_req) do { \
- struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
- _req->done(_req); \
-} while (0)
-
-
-/* Takes a request object and fills it in with the right magic */
-#define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \
- do { \
- (rpc)->uri = strdup(#name); \
- if ((rpc)->uri == NULL) { \
- fprintf(stderr, "failed to register object\n"); \
- exit(1); \
- } \
- (rpc)->request_new = (void *(*)(void))request##_new; \
- (rpc)->request_free = (void (*)(void *))request##_free; \
- (rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
- (rpc)->reply_new = (void *(*)(void))reply##_new; \
- (rpc)->reply_free = (void (*)(void *))reply##_free; \
- (rpc)->reply_complete = (int (*)(void *))reply##_complete; \
- (rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal; \
- } while (0)
-
-struct evrpc_base;
-struct evhttp;
-
-/* functions to start up the rpc system */
-
-/** Creates a new rpc base from which RPC requests can be received
- *
- * @param server a pointer to an existing HTTP server
- * @return a newly allocated evrpc_base struct
- * @see evrpc_free()
- */
-struct evrpc_base *evrpc_init(struct evhttp *server);
-
-/**
- * Frees the evrpc base
- *
- * For now, you are responsible for making sure that no rpcs are ongoing.
- *
- * @param base the evrpc_base object to be freed
- * @see evrpc_init
- */
-void evrpc_free(struct evrpc_base *base);
-
-/** register RPCs with the HTTP Server
- *
- * registers a new RPC with the HTTP server, each RPC needs to have
- * a unique name under which it can be identified.
- *
- * @param base the evrpc_base structure in which the RPC should be
- * registered.
- * @param name the name of the RPC
- * @param request the name of the RPC request structure
- * @param reply the name of the RPC reply structure
- * @param callback the callback that should be invoked when the RPC
- * is received. The callback has the following prototype
- * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
- * @param cbarg an additional parameter that can be passed to the callback.
- * The parameter can be used to carry around state.
- */
-#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
- do { \
- struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \
- EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \
- evrpc_register_rpc(base, rpc, \
- (void (*)(struct evrpc_req_generic*, void *))callback, cbarg); \
- } while (0)
-
-int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
- void (*)(struct evrpc_req_generic*, void *), void *);
-
-/**
- * Unregisters an already registered RPC
- *
- * @param base the evrpc_base object from which to unregister an RPC
- * @param name the name of the rpc to unregister
- * @return -1 on error or 0 when successful.
- * @see EVRPC_REGISTER()
- */
-#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name)
-
-int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
-
-/*
- * Client-side RPC support
- */
-
-struct evrpc_pool;
-struct evhttp_connection;
-
-/**
- * provides information about the completed RPC request.
- */
-struct evrpc_status {
-#define EVRPC_STATUS_ERR_NONE 0
-#define EVRPC_STATUS_ERR_TIMEOUT 1
-#define EVRPC_STATUS_ERR_BADPAYLOAD 2
-#define EVRPC_STATUS_ERR_UNSTARTED 3
-#define EVRPC_STATUS_ERR_HOOKABORTED 4
- int error;
-
- /* for looking at headers or other information */
- struct evhttp_request *http_req;
-};
-
-struct evrpc_request_wrapper {
- TAILQ_ENTRY(evrpc_request_wrapper) next;
-
- /* pool on which this rpc request is being made */
- struct evrpc_pool *pool;
-
- /* connection on which the request is being sent */
- struct evhttp_connection *evcon;
-
- /* event for implementing request timeouts */
- struct event ev_timeout;
-
- /* the name of the rpc */
- char *name;
-
- /* callback */
- void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
- void *cb_arg;
-
- void *request;
- void *reply;
-
- /* unmarshals the buffer into the proper request structure */
- void (*request_marshal)(struct evbuffer *, void *);
-
- /* removes all stored state in the reply */
- void (*reply_clear)(void *);
-
- /* marshals the reply into a buffer */
- int (*reply_unmarshal)(void *, struct evbuffer*);
-};
-
-/** launches an RPC and sends it to the server
- *
- * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
- *
- * @param name the name of the RPC
- * @param pool the evrpc_pool that contains the connection objects over which
- * the request should be sent.
- * @param request a pointer to the RPC request structure - it contains the
- * data to be sent to the server.
- * @param reply a pointer to the RPC reply structure. It is going to be filled
- * if the request was answered successfully
- * @param cb the callback to invoke when the RPC request has been answered
- * @param cbarg an additional argument to be passed to the client
- * @return 0 on success, -1 on failure
- */
-#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \
- evrpc_send_request_##name(pool, request, reply, cb, cbarg)
-
-int evrpc_make_request(struct evrpc_request_wrapper *);
-
-/** creates an rpc connection pool
- *
- * a pool has a number of connections associated with it.
- * rpc requests are always made via a pool.
- *
- * @param base a pointer to an struct event_based object; can be left NULL
- * in singled-threaded applications
- * @return a newly allocated struct evrpc_pool object
- * @see evrpc_pool_free()
- */
-struct evrpc_pool *evrpc_pool_new(struct event_base *base);
-/** frees an rpc connection pool
- *
- * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
- * @see evrpc_pool_new()
- */
-void evrpc_pool_free(struct evrpc_pool *pool);
-/*
- * adds a connection over which rpc can be dispatched. the connection
- * object must have been newly created.
- */
-void evrpc_pool_add_connection(struct evrpc_pool *,
- struct evhttp_connection *);
-
-/**
- * Sets the timeout in secs after which a request has to complete. The
- * RPC is completely aborted if it does not complete by then. Setting
- * the timeout to 0 means that it never timeouts and can be used to
- * implement callback type RPCs.
- *
- * Any connection already in the pool will be updated with the new
- * timeout. Connections added to the pool after set_timeout has be
- * called receive the pool timeout only if no timeout has been set
- * for the connection itself.
- *
- * @param pool a pointer to a struct evrpc_pool object
- * @param timeout_in_secs the number of seconds after which a request should
- * timeout and a failure be returned to the callback.
- */
-void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
-
-/**
- * Hooks for changing the input and output of RPCs; this can be used to
- * implement compression, authentication, encryption, ...
- */
-
-enum EVRPC_HOOK_TYPE {
- EVRPC_INPUT, /**< apply the function to an input hook */
- EVRPC_OUTPUT /**< apply the function to an output hook */
-};
-
-#ifndef WIN32
-/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it
- * conflicts with platform headers. */
-#define INPUT EVRPC_INPUT
-/** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it
- * conflicts with platform headers. */
-#define OUTPUT EVRPC_OUTPUT
-#endif
-
-/** adds a processing hook to either an rpc base or rpc pool
- *
- * If a hook returns -1, the processing is aborted.
- *
- * The add functions return handles that can be used for removing hooks.
- *
- * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
- * @param hook_type either INPUT or OUTPUT
- * @param cb the callback to call when the hook is activated
- * @param cb_arg an additional argument for the callback
- * @return a handle to the hook so it can be removed later
- * @see evrpc_remove_hook()
- */
-void *evrpc_add_hook(void *vbase,
- enum EVRPC_HOOK_TYPE hook_type,
- int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
- void *cb_arg);
-
-/** removes a previously added hook
- *
- * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
- * @param hook_type either INPUT or OUTPUT
- * @param handle a handle returned by evrpc_add_hook()
- * @return 1 on success or 0 on failure
- * @see evrpc_add_hook()
- */
-int evrpc_remove_hook(void *vbase,
- enum EVRPC_HOOK_TYPE hook_type,
- void *handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _EVRPC_H_ */
diff --git a/lib/libevent/evsignal.h b/lib/libevent/evsignal.h
deleted file mode 100644
index 56add501efc..00000000000
--- a/lib/libevent/evsignal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* $NetBSD: evsignal.h,v 1.4 2009/07/08 21:23:53 tls Exp $ */
-
-/*
- * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVSIGNAL_H_
-#define _EVSIGNAL_H_
-
-typedef void (*ev_sighandler_t)(int);
-
-struct evsignal_info {
- struct event ev_signal;
- int ev_signal_pair[2];
- int ev_signal_added;
- volatile sig_atomic_t evsignal_caught;
- struct event_list evsigevents[NSIG];
- sig_atomic_t evsigcaught[NSIG];
-#ifdef HAVE_SIGACTION
- struct sigaction **sh_old;
-#else
- ev_sighandler_t **sh_old;
-#endif
- int sh_old_max;
-};
-void evsignal_init(struct event_base *);
-void evsignal_process(struct event_base *);
-int evsignal_add(struct event *);
-int evsignal_del(struct event *);
-void evsignal_dealloc(struct event_base *);
-
-#endif /* _EVSIGNAL_H_ */
diff --git a/lib/libevent/evutil.c b/lib/libevent/evutil.c
deleted file mode 100644
index 0781a305b01..00000000000
--- a/lib/libevent/evutil.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/* $NetBSD: evutil.c,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-#include <stdio.h>
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <errno.h>
-
-#include "evutil.h"
-#include "log.h"
-
-int
-evutil_socketpair(int family, int type, int protocol, int fd[2])
-{
- return socketpair(family, type, protocol, fd);
-}
-
-int
-evutil_make_socket_nonblocking(int fd)
-{
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
- event_warn("fcntl(O_NONBLOCK)");
- return -1;
- }
-
- return 0;
-}
-
-ev_int64_t
-evutil_strtoll(const char *s, char **endptr, int base)
-{
-#ifdef HAVE_STRTOLL
- return (ev_int64_t)strtoll(s, endptr, base);
-#elif SIZEOF_LONG == 8
- return (ev_int64_t)strtol(s, endptr, base);
-#else
-#error "I don't know how to parse 64-bit integers."
-#endif
-}
-int
-evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
-{
- int r;
- va_list ap;
- va_start(ap, format);
- r = evutil_vsnprintf(buf, buflen, format, ap);
- va_end(ap);
- return r;
-}
-
-int
-evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
-{
- int r = vsnprintf(buf, buflen, format, ap);
- buf[buflen-1] = '\0';
- return r;
-}
diff --git a/lib/libevent/evutil.h b/lib/libevent/evutil.h
deleted file mode 100644
index c56cf2fea28..00000000000
--- a/lib/libevent/evutil.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* $NetBSD: evutil.h,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _EVUTIL_H_
-#define _EVUTIL_H_
-
-/** @file evutil.h
-
- Common convenience functions for cross-platform portability and
- related socket manipulations.
-
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <stdarg.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdint.h>
-
-#define ev_uint64_t uint64_t
-#define ev_int64_t int64_t
-#define ev_uint32_t uint32_t
-#define ev_uint16_t uint16_t
-#define ev_uint8_t uint8_t
-
-int evutil_socketpair(int d, int type, int protocol, int sv[2]);
-int evutil_make_socket_nonblocking(int sock);
-#define EVUTIL_CLOSESOCKET(s) close(s)
-
-#define EVUTIL_SOCKET_ERROR() (errno)
-#define EVUTIL_SET_SOCKET_ERROR(errcode) \
- do { errno = (errcode); } while (0)
-
-/*
- * Manipulation functions for struct timeval
- */
-#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp))
-#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp))
-
-#define evutil_timerclear(tvp) timerclear(tvp)
-
-#define evutil_timercmp(tvp, uvp, cmp) \
- (((tvp)->tv_sec == (uvp)->tv_sec) ? \
- ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
- ((tvp)->tv_sec cmp (uvp)->tv_sec))
-
-#define evutil_timerisset(tvp) timerisset(tvp)
-
-
-/* big-int related functions */
-ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
-
-
-#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
-
-int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
-#ifdef __GNUC__
- __attribute__((format(printf, 3, 4)))
-#endif
- ;
-int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _EVUTIL_H_ */
diff --git a/lib/libevent/http-internal.h b/lib/libevent/http-internal.h
deleted file mode 100644
index 1df7405c2a5..00000000000
--- a/lib/libevent/http-internal.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* $NetBSD: http-internal.h,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright 2001 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * This header file contains definitions for dealing with HTTP requests
- * that are internal to libevent. As user of the library, you should not
- * need to know about these.
- */
-
-#ifndef _HTTP_H_
-#define _HTTP_H_
-
-#define HTTP_CONNECT_TIMEOUT 45
-#define HTTP_WRITE_TIMEOUT 50
-#define HTTP_READ_TIMEOUT 50
-
-#define HTTP_PREFIX "http://"
-#define HTTP_DEFAULTPORT 80
-
-enum message_read_status {
- ALL_DATA_READ = 1,
- MORE_DATA_EXPECTED = 0,
- DATA_CORRUPTED = -1,
- REQUEST_CANCELED = -2
-};
-
-enum evhttp_connection_error {
- EVCON_HTTP_TIMEOUT,
- EVCON_HTTP_EOF,
- EVCON_HTTP_INVALID_HEADER
-};
-
-struct evbuffer;
-struct addrinfo;
-struct evhttp_request;
-
-/* A stupid connection object - maybe make this a bufferevent later */
-
-enum evhttp_connection_state {
- EVCON_DISCONNECTED, /**< not currently connected not trying either*/
- EVCON_CONNECTING, /**< tries to currently connect */
- EVCON_IDLE, /**< connection is established */
- EVCON_READING_FIRSTLINE,/**< reading Request-Line (incoming conn) or
- **< Status-Line (outgoing conn) */
- EVCON_READING_HEADERS, /**< reading request/response headers */
- EVCON_READING_BODY, /**< reading request/response body */
- EVCON_READING_TRAILER, /**< reading request/response chunked trailer */
- EVCON_WRITING /**< writing request/response headers/body */
-};
-
-struct event_base;
-
-struct evhttp_connection {
- /* we use tailq only if they were created for an http server */
- TAILQ_ENTRY(evhttp_connection) (next);
-
- int fd;
- struct event ev;
- struct event close_ev;
- struct evbuffer *input_buffer;
- struct evbuffer *output_buffer;
-
- char *bind_address; /* address to use for binding the src */
- u_short bind_port; /* local port for binding the src */
-
- char *address; /* address to connect to */
- u_short port;
-
- int flags;
-#define EVHTTP_CON_INCOMING 0x0001 /* only one request on it ever */
-#define EVHTTP_CON_OUTGOING 0x0002 /* multiple requests possible */
-#define EVHTTP_CON_CLOSEDETECT 0x0004 /* detecting if persistent close */
-
- int timeout; /* timeout in seconds for events */
- int retry_cnt; /* retry count */
- int retry_max; /* maximum number of retries */
-
- enum evhttp_connection_state state;
-
- /* for server connections, the http server they are connected with */
- struct evhttp *http_server;
-
- TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
-
- void (*cb)(struct evhttp_connection *, void *);
- void *cb_arg;
-
- void (*closecb)(struct evhttp_connection *, void *);
- void *closecb_arg;
-
- struct event_base *base;
-};
-
-struct evhttp_cb {
- TAILQ_ENTRY(evhttp_cb) next;
-
- char *what;
-
- void (*cb)(struct evhttp_request *req, void *);
- void *cbarg;
-};
-
-/* both the http server as well as the rpc system need to queue connections */
-TAILQ_HEAD(evconq, evhttp_connection);
-
-/* each bound socket is stored in one of these */
-struct evhttp_bound_socket {
- TAILQ_ENTRY(evhttp_bound_socket) (next);
-
- struct event bind_ev;
-};
-
-struct evhttp {
- TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
-
- TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
- struct evconq connections;
-
- int timeout;
-
- void (*gencb)(struct evhttp_request *req, void *);
- void *gencbarg;
-
- struct event_base *base;
-};
-
-/* resets the connection; can be reused for more requests */
-void evhttp_connection_reset(struct evhttp_connection *);
-
-/* connects if necessary */
-int evhttp_connection_connect(struct evhttp_connection *);
-
-/* notifies the current request that it failed; resets connection */
-void evhttp_connection_fail(struct evhttp_connection *,
- enum evhttp_connection_error error);
-
-void evhttp_get_request(struct evhttp *, int, struct sockaddr *, socklen_t);
-
-int evhttp_hostportfile(char *, char **, u_short *, char **);
-
-int evhttp_parse_firstline(struct evhttp_request *, struct evbuffer*);
-int evhttp_parse_headers(struct evhttp_request *, struct evbuffer*);
-
-void evhttp_start_read(struct evhttp_connection *);
-void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
-
-void evhttp_write_buffer(struct evhttp_connection *,
- void (*)(struct evhttp_connection *, void *), void *);
-
-/* response sending HTML the data in the buffer */
-void evhttp_response_code(struct evhttp_request *, int, const char *);
-void evhttp_send_page(struct evhttp_request *, struct evbuffer *);
-
-#endif /* _HTTP_H */
diff --git a/lib/libevent/http.c b/lib/libevent/http.c
deleted file mode 100644
index eb9a522554a..00000000000
--- a/lib/libevent/http.c
+++ /dev/null
@@ -1,2748 +0,0 @@
-/* $NetBSD: http.c,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_IOCCOM_H
-#include <sys/ioccom.h>
-#endif
-
-#include <sys/resource.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include <sys/queue.h>
-
-#include <netinet/in.h>
-#include <netdb.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#undef timeout_pending
-#undef timeout_initialized
-
-#include "event.h"
-#include "evhttp.h"
-#include "evutil.h"
-#include "log.h"
-#include "http-internal.h"
-
-#ifndef HAVE_GETADDRINFO
-struct addrinfo {
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- size_t ai_addrlen;
- struct sockaddr *ai_addr;
- struct addrinfo *ai_next;
-};
-static int
-fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
-{
- struct hostent *he = NULL;
- struct sockaddr_in *sa;
- if (hostname) {
- he = gethostbyname(hostname);
- if (!he)
- return (-1);
- }
- ai->ai_family = he ? he->h_addrtype : AF_INET;
- ai->ai_socktype = SOCK_STREAM;
- ai->ai_protocol = 0;
- ai->ai_addrlen = sizeof(struct sockaddr_in);
- if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen)))
- return (-1);
- sa = (struct sockaddr_in*)ai->ai_addr;
- memset(sa, 0, ai->ai_addrlen);
- if (he) {
- sa->sin_family = he->h_addrtype;
- memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);
- } else {
- sa->sin_family = AF_INET;
- sa->sin_addr.s_addr = INADDR_ANY;
- }
- ai->ai_next = NULL;
- return (0);
-}
-static void
-fake_freeaddrinfo(struct addrinfo *ai)
-{
- free(ai->ai_addr);
-}
-#endif
-
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-/* wrapper for setting the base from the http server */
-#define EVHTTP_BASE_SET(x, y) do { \
- if ((x)->base != NULL) event_base_set((x)->base, y); \
-} while (0)
-
-extern int debug;
-
-static int socket_connect(int fd, const char *address, unsigned short port);
-static int bind_socket_ai(struct addrinfo *, int reuse);
-static int bind_socket(const char *, u_short, int reuse);
-static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
-static int evhttp_associate_new_request_with_connection(
- struct evhttp_connection *evcon);
-static void evhttp_connection_start_detectclose(
- struct evhttp_connection *evcon);
-static void evhttp_connection_stop_detectclose(
- struct evhttp_connection *evcon);
-static void evhttp_request_dispatch(struct evhttp_connection* evcon);
-static void evhttp_read_firstline(struct evhttp_connection *evcon,
- struct evhttp_request *req);
-static void evhttp_read_header(struct evhttp_connection *evcon,
- struct evhttp_request *req);
-static int evhttp_add_header_internal(struct evkeyvalq *headers,
- const char *key, const char *value);
-static int evhttp_decode_uri_internal(const char *uri, size_t length,
- char *ret, int always_decode_plus);
-
-void evhttp_read(int, short, void *);
-void evhttp_write(int, short, void *);
-
-#ifndef HAVE_STRSEP
-/* strsep replacement for platforms that lack it. Only works if
- * del is one character long. */
-static char *
-strsep(char **s, const char *del)
-{
- char *d, *tok;
- assert(strlen(del) == 1);
- if (!s || !*s)
- return NULL;
- tok = *s;
- d = strstr(tok, del);
- if (d) {
- *d = '\0';
- *s = d + 1;
- } else
- *s = NULL;
- return tok;
-}
-#endif
-
-static const char *
-html_replace(char ch, char *buf)
-{
- switch (ch) {
- case '<':
- return "&lt;";
- case '>':
- return "&gt;";
- case '"':
- return "&quot;";
- case '\'':
- return "&#039;";
- case '&':
- return "&amp;";
- default:
- break;
- }
-
- /* Echo the character back */
- buf[0] = ch;
- buf[1] = '\0';
-
- return buf;
-}
-
-/*
- * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
- * &#039; and &amp; correspondingly.
- *
- * The returned string needs to be freed by the caller.
- */
-
-char *
-evhttp_htmlescape(const char *html)
-{
- int i, new_size = 0, old_size = strlen(html);
- char *escaped_html, *p;
- char scratch_space[2];
-
- for (i = 0; i < old_size; ++i)
- new_size += strlen(html_replace(html[i], scratch_space));
-
- p = escaped_html = malloc(new_size + 1);
- if (escaped_html == NULL)
- event_err(1, "%s: malloc(%d)", __func__, new_size + 1);
- for (i = 0; i < old_size; ++i) {
- const char *replaced = html_replace(html[i], scratch_space);
- /* this is length checked */
- strcpy(p, replaced);
- p += strlen(replaced);
- }
-
- *p = '\0';
-
- return (escaped_html);
-}
-
-static const char *
-evhttp_method(enum evhttp_cmd_type type)
-{
- const char *method;
-
- switch (type) {
- case EVHTTP_REQ_GET:
- method = "GET";
- break;
- case EVHTTP_REQ_POST:
- method = "POST";
- break;
- case EVHTTP_REQ_HEAD:
- method = "HEAD";
- break;
- default:
- method = NULL;
- break;
- }
-
- return (method);
-}
-
-static void
-evhttp_add_event(struct event *ev, int timeout, int default_timeout)
-{
- if (timeout != 0) {
- struct timeval tv;
-
- evutil_timerclear(&tv);
- tv.tv_sec = timeout != -1 ? timeout : default_timeout;
- event_add(ev, &tv);
- } else {
- event_add(ev, NULL);
- }
-}
-
-void
-evhttp_write_buffer(struct evhttp_connection *evcon,
- void (*cb)(struct evhttp_connection *, void *), void *arg)
-{
- event_debug(("%s: preparing to write buffer\n", __func__));
-
- /* Set call back */
- evcon->cb = cb;
- evcon->cb_arg = arg;
-
- /* check if the event is already pending */
- if (event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL))
- event_del(&evcon->ev);
-
- event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon);
- EVHTTP_BASE_SET(evcon, &evcon->ev);
- evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT);
-}
-
-static int
-evhttp_connected(struct evhttp_connection *evcon)
-{
- switch (evcon->state) {
- case EVCON_DISCONNECTED:
- case EVCON_CONNECTING:
- return (0);
- case EVCON_IDLE:
- case EVCON_READING_FIRSTLINE:
- case EVCON_READING_HEADERS:
- case EVCON_READING_BODY:
- case EVCON_READING_TRAILER:
- case EVCON_WRITING:
- default:
- return (1);
- }
-}
-
-/*
- * Create the headers needed for an HTTP request
- */
-static void
-evhttp_make_header_request(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- const char *method;
-
- evhttp_remove_header(req->output_headers, "Proxy-Connection");
-
- /* Generate request line */
- method = evhttp_method(req->type);
- evbuffer_add_printf(evcon->output_buffer, "%s %s HTTP/%d.%d\r\n",
- method, req->uri, req->major, req->minor);
-
- /* Add the content length on a post request if missing */
- if (req->type == EVHTTP_REQ_POST &&
- evhttp_find_header(req->output_headers, "Content-Length") == NULL){
- char size[12];
- evutil_snprintf(size, sizeof(size), "%ld",
- (long)EVBUFFER_LENGTH(req->output_buffer));
- evhttp_add_header(req->output_headers, "Content-Length", size);
- }
-}
-
-static int
-evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
-{
- if (flags & EVHTTP_PROXY_REQUEST) {
- /* proxy connection */
- const char *connection = evhttp_find_header(headers, "Proxy-Connection");
- return (connection == NULL || strcasecmp(connection, "keep-alive") != 0);
- } else {
- const char *connection = evhttp_find_header(headers, "Connection");
- return (connection != NULL && strcasecmp(connection, "close") == 0);
- }
-}
-
-static int
-evhttp_is_connection_keepalive(struct evkeyvalq* headers)
-{
- const char *connection = evhttp_find_header(headers, "Connection");
- return (connection != NULL
- && strncasecmp(connection, "keep-alive", 10) == 0);
-}
-
-static void
-evhttp_maybe_add_date_header(struct evkeyvalq *headers)
-{
- if (evhttp_find_header(headers, "Date") == NULL) {
- char date[50];
- struct tm cur;
- struct tm *cur_p;
- time_t t = time(NULL);
-
- gmtime_r(&t, &cur);
- cur_p = &cur;
-
- if (strftime(date, sizeof(date),
- "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
- evhttp_add_header(headers, "Date", date);
- }
- }
-}
-
-static void
-evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
- long content_length)
-{
- if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
- evhttp_find_header(headers, "Content-Length") == NULL) {
- char len[12];
- evutil_snprintf(len, sizeof(len), "%ld", content_length);
- evhttp_add_header(headers, "Content-Length", len);
- }
-}
-
-/*
- * Create the headers needed for an HTTP reply
- */
-
-static void
-evhttp_make_header_response(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
- evbuffer_add_printf(evcon->output_buffer, "HTTP/%d.%d %d %s\r\n",
- req->major, req->minor, req->response_code,
- req->response_code_line);
-
- if (req->major == 1) {
- if (req->minor == 1)
- evhttp_maybe_add_date_header(req->output_headers);
-
- /*
- * if the protocol is 1.0; and the connection was keep-alive
- * we need to add a keep-alive header, too.
- */
- if (req->minor == 0 && is_keepalive)
- evhttp_add_header(req->output_headers,
- "Connection", "keep-alive");
-
- if (req->minor == 1 || is_keepalive) {
- /*
- * we need to add the content length if the
- * user did not give it, this is required for
- * persistent connections to work.
- */
- evhttp_maybe_add_content_length_header(
- req->output_headers,
- (long)EVBUFFER_LENGTH(req->output_buffer));
- }
- }
-
- /* Potentially add headers for unidentified content. */
- if (EVBUFFER_LENGTH(req->output_buffer)) {
- if (evhttp_find_header(req->output_headers,
- "Content-Type") == NULL) {
- evhttp_add_header(req->output_headers,
- "Content-Type", "text/html; charset=ISO-8859-1");
- }
- }
-
- /* if the request asked for a close, we send a close, too */
- if (evhttp_is_connection_close(req->flags, req->input_headers)) {
- evhttp_remove_header(req->output_headers, "Connection");
- if (!(req->flags & EVHTTP_PROXY_REQUEST))
- evhttp_add_header(req->output_headers, "Connection", "close");
- evhttp_remove_header(req->output_headers, "Proxy-Connection");
- }
-}
-
-void
-evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- struct evkeyval *header;
-
- /*
- * Depending if this is a HTTP request or response, we might need to
- * add some new headers or remove existing headers.
- */
- if (req->kind == EVHTTP_REQUEST) {
- evhttp_make_header_request(evcon, req);
- } else {
- evhttp_make_header_response(evcon, req);
- }
-
- TAILQ_FOREACH(header, req->output_headers, next) {
- evbuffer_add_printf(evcon->output_buffer, "%s: %s\r\n",
- header->key, header->value);
- }
- evbuffer_add(evcon->output_buffer, "\r\n", 2);
-
- if (EVBUFFER_LENGTH(req->output_buffer) > 0) {
- /*
- * For a request, we add the POST data, for a reply, this
- * is the regular data.
- */
- evbuffer_add_buffer(evcon->output_buffer, req->output_buffer);
- }
-}
-
-/* Separated host, port and file from URI */
-
-int
-evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
-{
- /* XXX not threadsafe. */
- static char host[1024];
- static char file[1024];
- char *p;
- const char *p2;
- int len;
- u_short port;
-
- len = strlen(HTTP_PREFIX);
- if (strncasecmp(url, HTTP_PREFIX, len))
- return (-1);
-
- url += len;
-
- /* We might overrun */
- if (strlcpy(host, url, sizeof (host)) >= sizeof(host))
- return (-1);
-
- p = strchr(host, '/');
- if (p != NULL) {
- *p = '\0';
- p2 = p + 1;
- } else
- p2 = NULL;
-
- if (pfile != NULL) {
- /* Generate request file */
- if (p2 == NULL)
- p2 = "";
- evutil_snprintf(file, sizeof(file), "/%s", p2);
- }
-
- p = strchr(host, ':');
- if (p != NULL) {
- *p = '\0';
- port = atoi(p + 1);
-
- if (port == 0)
- return (-1);
- } else
- port = HTTP_DEFAULTPORT;
-
- if (phost != NULL)
- *phost = host;
- if (pport != NULL)
- *pport = port;
- if (pfile != NULL)
- *pfile = file;
-
- return (0);
-}
-
-static int
-evhttp_connection_incoming_fail(struct evhttp_request *req,
- enum evhttp_connection_error error)
-{
- switch (error) {
- case EVCON_HTTP_TIMEOUT:
- case EVCON_HTTP_EOF:
- /*
- * these are cases in which we probably should just
- * close the connection and not send a reply. this
- * case may happen when a browser keeps a persistent
- * connection open and we timeout on the read.
- */
- return (-1);
- case EVCON_HTTP_INVALID_HEADER:
- default: /* xxx: probably should just error on default */
- /* the callback looks at the uri to determine errors */
- if (req->uri) {
- free(req->uri);
- req->uri = NULL;
- }
-
- /*
- * the callback needs to send a reply, once the reply has
- * been send, the connection should get freed.
- */
- (*req->cb)(req, req->cb_arg);
- }
-
- return (0);
-}
-
-void
-evhttp_connection_fail(struct evhttp_connection *evcon,
- enum evhttp_connection_error error)
-{
- struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
- void (*cb)(struct evhttp_request *, void *);
- void *cb_arg;
- assert(req != NULL);
-
- if (evcon->flags & EVHTTP_CON_INCOMING) {
- /*
- * for incoming requests, there are two different
- * failure cases. it's either a network level error
- * or an http layer error. for problems on the network
- * layer like timeouts we just drop the connections.
- * For HTTP problems, we might have to send back a
- * reply before the connection can be freed.
- */
- if (evhttp_connection_incoming_fail(req, error) == -1)
- evhttp_connection_free(evcon);
- return;
- }
-
- /* save the callback for later; the cb might free our object */
- cb = req->cb;
- cb_arg = req->cb_arg;
-
- TAILQ_REMOVE(&evcon->requests, req, next);
- evhttp_request_free(req);
-
- /* xxx: maybe we should fail all requests??? */
-
- /* reset the connection */
- evhttp_connection_reset(evcon);
-
- /* We are trying the next request that was queued on us */
- if (TAILQ_FIRST(&evcon->requests) != NULL)
- evhttp_connection_connect(evcon);
-
- /* inform the user */
- if (cb != NULL)
- (*cb)(NULL, cb_arg);
-}
-
-void
-evhttp_write(int fd, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- int n;
-
- if (what == EV_TIMEOUT) {
- evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
- return;
- }
-
- n = evbuffer_write(evcon->output_buffer, fd);
- if (n == -1) {
- event_debug(("%s: evbuffer_write", __func__));
- evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
- return;
- }
-
- if (n == 0) {
- event_debug(("%s: write nothing", __func__));
- evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
- return;
- }
-
- if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
- evhttp_add_event(&evcon->ev,
- evcon->timeout, HTTP_WRITE_TIMEOUT);
- return;
- }
-
- /* Activate our call back */
- if (evcon->cb != NULL)
- (*evcon->cb)(evcon, evcon->cb_arg);
-}
-
-/**
- * Advance the connection state.
- * - If this is an outgoing connection, we've just processed the response;
- * idle or close the connection.
- * - If this is an incoming connection, we've just processed the request;
- * respond.
- */
-static void
-evhttp_connection_done(struct evhttp_connection *evcon)
-{
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
- int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
-
- if (con_outgoing) {
- /* idle or close the connection */
- int need_close;
- TAILQ_REMOVE(&evcon->requests, req, next);
- req->evcon = NULL;
-
- evcon->state = EVCON_IDLE;
-
- need_close =
- evhttp_is_connection_close(req->flags, req->input_headers)||
- evhttp_is_connection_close(req->flags, req->output_headers);
-
- /* check if we got asked to close the connection */
- if (need_close)
- evhttp_connection_reset(evcon);
-
- if (TAILQ_FIRST(&evcon->requests) != NULL) {
- /*
- * We have more requests; reset the connection
- * and deal with the next request.
- */
- if (!evhttp_connected(evcon))
- evhttp_connection_connect(evcon);
- else
- evhttp_request_dispatch(evcon);
- } else if (!need_close) {
- /*
- * The connection is going to be persistent, but we
- * need to detect if the other side closes it.
- */
- evhttp_connection_start_detectclose(evcon);
- }
- } else {
- /*
- * incoming connection - we need to leave the request on the
- * connection so that we can reply to it.
- */
- evcon->state = EVCON_WRITING;
- }
-
- /* notify the user of the request */
- (*req->cb)(req, req->cb_arg);
-
- /* if this was an outgoing request, we own and it's done. so free it */
- if (con_outgoing) {
- evhttp_request_free(req);
- }
-}
-
-/*
- * Handles reading from a chunked request.
- * return ALL_DATA_READ:
- * all data has been read
- * return MORE_DATA_EXPECTED:
- * more data is expected
- * return DATA_CORRUPTED:
- * data is corrupted
- * return REQUEST_CANCLED:
- * request was canceled by the user calling evhttp_cancel_request
- */
-
-static enum message_read_status
-evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
-{
- int len;
-
- while ((len = EVBUFFER_LENGTH(buf)) > 0) {
- if (req->ntoread < 0) {
- /* Read chunk size */
- ev_int64_t ntoread;
- char *p = evbuffer_readline(buf);
- char *endp;
- int error;
- if (p == NULL)
- break;
- /* the last chunk is on a new line? */
- if (strlen(p) == 0) {
- free(p);
- continue;
- }
- ntoread = evutil_strtoll(p, &endp, 16);
- error = (*p == '\0' ||
- (*endp != '\0' && *endp != ' ') ||
- ntoread < 0);
- free(p);
- if (error) {
- /* could not get chunk size */
- return (DATA_CORRUPTED);
- }
- req->ntoread = ntoread;
- if (req->ntoread == 0) {
- /* Last chunk */
- return (ALL_DATA_READ);
- }
- continue;
- }
-
- /* don't have enough to complete a chunk; wait for more */
- if (len < req->ntoread)
- return (MORE_DATA_EXPECTED);
-
- /* Completed chunk */
- evbuffer_add(req->input_buffer,
- EVBUFFER_DATA(buf), (size_t)req->ntoread);
- evbuffer_drain(buf, (size_t)req->ntoread);
- req->ntoread = -1;
- if (req->chunk_cb != NULL) {
- (*req->chunk_cb)(req, req->cb_arg);
- evbuffer_drain(req->input_buffer,
- EVBUFFER_LENGTH(req->input_buffer));
- }
- }
-
- return (MORE_DATA_EXPECTED);
-}
-
-static void
-evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- struct evbuffer *buf = evcon->input_buffer;
-
- switch (evhttp_parse_headers(req, buf)) {
- case DATA_CORRUPTED:
- evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
- break;
- case ALL_DATA_READ:
- event_del(&evcon->ev);
- evhttp_connection_done(evcon);
- break;
- case MORE_DATA_EXPECTED:
- default:
- evhttp_add_event(&evcon->ev, evcon->timeout,
- HTTP_READ_TIMEOUT);
- break;
- }
-}
-
-static void
-evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- struct evbuffer *buf = evcon->input_buffer;
-
- if (req->chunked) {
- switch (evhttp_handle_chunked_read(req, buf)) {
- case ALL_DATA_READ:
- /* finished last chunk */
- evcon->state = EVCON_READING_TRAILER;
- evhttp_read_trailer(evcon, req);
- return;
- case DATA_CORRUPTED:
- /* corrupted data */
- evhttp_connection_fail(evcon,
- EVCON_HTTP_INVALID_HEADER);
- return;
- case REQUEST_CANCELED:
- /* request canceled */
- evhttp_request_free(req);
- return;
- case MORE_DATA_EXPECTED:
- default:
- break;
- }
- } else if (req->ntoread < 0) {
- /* Read until connection close. */
- evbuffer_add_buffer(req->input_buffer, buf);
- } else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
- /* Completed content length */
- evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
- (size_t)req->ntoread);
- evbuffer_drain(buf, (size_t)req->ntoread);
- req->ntoread = 0;
- evhttp_connection_done(evcon);
- return;
- }
- /* Read more! */
- event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
- EVHTTP_BASE_SET(evcon, &evcon->ev);
- evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
-}
-
-/*
- * Reads data into a buffer structure until no more data
- * can be read on the file descriptor or we have read all
- * the data that we wanted to read.
- * Execute callback when done.
- */
-
-void
-evhttp_read(int fd, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
- struct evbuffer *buf = evcon->input_buffer;
- int n, len;
-
- if (what == EV_TIMEOUT) {
- evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
- return;
- }
- n = evbuffer_read(buf, fd, -1);
- len = EVBUFFER_LENGTH(buf);
- event_debug(("%s: got %d on %d\n", __func__, n, fd));
-
- if (n == -1) {
- if (errno != EINTR && errno != EAGAIN) {
- event_debug(("%s: evbuffer_read", __func__));
- evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
- } else {
- evhttp_add_event(&evcon->ev, evcon->timeout,
- HTTP_READ_TIMEOUT);
- }
- return;
- } else if (n == 0) {
- /* Connection closed */
- evhttp_connection_done(evcon);
- return;
- }
-
- switch (evcon->state) {
- case EVCON_READING_FIRSTLINE:
- evhttp_read_firstline(evcon, req);
- break;
- case EVCON_READING_HEADERS:
- evhttp_read_header(evcon, req);
- break;
- case EVCON_READING_BODY:
- evhttp_read_body(evcon, req);
- break;
- case EVCON_READING_TRAILER:
- evhttp_read_trailer(evcon, req);
- break;
- case EVCON_DISCONNECTED:
- case EVCON_CONNECTING:
- case EVCON_IDLE:
- case EVCON_WRITING:
- default:
- event_errx(1, "%s: illegal connection state %d",
- __func__, evcon->state);
- }
-}
-
-static void
-evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
-{
- /* This is after writing the request to the server */
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
- assert(req != NULL);
-
- assert(evcon->state == EVCON_WRITING);
-
- /* We are done writing our header and are now expecting the response */
- req->kind = EVHTTP_RESPONSE;
-
- evhttp_start_read(evcon);
-}
-
-/*
- * Clean up a connection object
- */
-
-void
-evhttp_connection_free(struct evhttp_connection *evcon)
-{
- struct evhttp_request *req;
-
- /* notify interested parties that this connection is going down */
- if (evcon->fd != -1) {
- if (evhttp_connected(evcon) && evcon->closecb != NULL)
- (*evcon->closecb)(evcon, evcon->closecb_arg);
- }
-
- /* remove all requests that might be queued on this connection */
- while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
- TAILQ_REMOVE(&evcon->requests, req, next);
- evhttp_request_free(req);
- }
-
- if (evcon->http_server != NULL) {
- struct evhttp *http = evcon->http_server;
- TAILQ_REMOVE(&http->connections, evcon, next);
- }
-
- if (event_initialized(&evcon->close_ev))
- event_del(&evcon->close_ev);
-
- if (event_initialized(&evcon->ev))
- event_del(&evcon->ev);
-
- if (evcon->fd != -1)
- EVUTIL_CLOSESOCKET(evcon->fd);
-
- if (evcon->bind_address != NULL)
- free(evcon->bind_address);
-
- if (evcon->address != NULL)
- free(evcon->address);
-
- if (evcon->input_buffer != NULL)
- evbuffer_free(evcon->input_buffer);
-
- if (evcon->output_buffer != NULL)
- evbuffer_free(evcon->output_buffer);
-
- free(evcon);
-}
-
-void
-evhttp_connection_set_local_address(struct evhttp_connection *evcon,
- const char *address)
-{
- assert(evcon->state == EVCON_DISCONNECTED);
- if (evcon->bind_address)
- free(evcon->bind_address);
- if ((evcon->bind_address = strdup(address)) == NULL)
- event_err(1, "%s: strdup", __func__);
-}
-
-void
-evhttp_connection_set_local_port(struct evhttp_connection *evcon,
- unsigned short port)
-{
- assert(evcon->state == EVCON_DISCONNECTED);
- evcon->bind_port = port;
-}
-
-static void
-evhttp_request_dispatch(struct evhttp_connection* evcon)
-{
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
-
- /* this should not usually happy but it's possible */
- if (req == NULL)
- return;
-
- /* delete possible close detection events */
- evhttp_connection_stop_detectclose(evcon);
-
- /* we assume that the connection is connected already */
- assert(evcon->state == EVCON_IDLE);
-
- evcon->state = EVCON_WRITING;
-
- /* Create the header from the store arguments */
- evhttp_make_header(evcon, req);
-
- evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
-}
-
-/* Reset our connection state */
-void
-evhttp_connection_reset(struct evhttp_connection *evcon)
-{
- if (event_initialized(&evcon->ev))
- event_del(&evcon->ev);
-
- if (evcon->fd != -1) {
- /* inform interested parties about connection close */
- if (evhttp_connected(evcon) && evcon->closecb != NULL)
- (*evcon->closecb)(evcon, evcon->closecb_arg);
-
- EVUTIL_CLOSESOCKET(evcon->fd);
- evcon->fd = -1;
- }
- evcon->state = EVCON_DISCONNECTED;
-
- evbuffer_drain(evcon->input_buffer,
- EVBUFFER_LENGTH(evcon->input_buffer));
- evbuffer_drain(evcon->output_buffer,
- EVBUFFER_LENGTH(evcon->output_buffer));
-}
-
-static void
-evhttp_detect_close_cb(int fd, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- evhttp_connection_reset(evcon);
-}
-
-static void
-evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
-{
- evcon->flags |= EVHTTP_CON_CLOSEDETECT;
-
- if (event_initialized(&evcon->close_ev))
- event_del(&evcon->close_ev);
- event_set(&evcon->close_ev, evcon->fd, EV_READ,
- evhttp_detect_close_cb, evcon);
- EVHTTP_BASE_SET(evcon, &evcon->close_ev);
- event_add(&evcon->close_ev, NULL);
-}
-
-static void
-evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
-{
- evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
- event_del(&evcon->close_ev);
-}
-
-static void
-evhttp_connection_retry(int fd, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
-
- evcon->state = EVCON_DISCONNECTED;
- evhttp_connection_connect(evcon);
-}
-
-/*
- * Call back for asynchronous connection attempt.
- */
-
-static void
-evhttp_connectioncb(int fd, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- int error;
- socklen_t errsz = sizeof(error);
-
- if (what == EV_TIMEOUT) {
- event_debug(("%s: connection timeout for \"%s:%d\" on %d",
- __func__, evcon->address, evcon->port, evcon->fd));
- goto cleanup;
- }
-
- /* Check if the connection completed */
- if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
- &errsz) == -1) {
- event_debug(("%s: getsockopt for \"%s:%d\" on %d",
- __func__, evcon->address, evcon->port, evcon->fd));
- goto cleanup;
- }
-
- if (error) {
- event_debug(("%s: connect failed for \"%s:%d\" on %d: %s",
- __func__, evcon->address, evcon->port, evcon->fd,
- strerror(error)));
- goto cleanup;
- }
-
- /* We are connected to the server now */
- event_debug(("%s: connected to \"%s:%d\" on %d\n",
- __func__, evcon->address, evcon->port, evcon->fd));
-
- /* Reset the retry count as we were successful in connecting */
- evcon->retry_cnt = 0;
- evcon->state = EVCON_IDLE;
-
- /* try to start requests that have queued up on this connection */
- evhttp_request_dispatch(evcon);
- return;
-
- cleanup:
- if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
- evtimer_set(&evcon->ev, evhttp_connection_retry, evcon);
- EVHTTP_BASE_SET(evcon, &evcon->ev);
- evhttp_add_event(&evcon->ev, MIN(3600, 2 << evcon->retry_cnt),
- HTTP_CONNECT_TIMEOUT);
- evcon->retry_cnt++;
- return;
- }
- evhttp_connection_reset(evcon);
-
- /* for now, we just signal all requests by executing their callbacks */
- while (TAILQ_FIRST(&evcon->requests) != NULL) {
- struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
- TAILQ_REMOVE(&evcon->requests, request, next);
- request->evcon = NULL;
-
- /* we might want to set an error here */
- request->cb(request, request->cb_arg);
- evhttp_request_free(request);
- }
-}
-
-/*
- * Check if we got a valid response code.
- */
-
-static int
-evhttp_valid_response_code(int code)
-{
- if (code == 0)
- return (0);
-
- return (1);
-}
-
-/* Parses the status line of a web server */
-
-static int
-evhttp_parse_response_line(struct evhttp_request *req, char *line)
-{
- char *protocol;
- char *number;
- char *readable;
-
- protocol = strsep(&line, " ");
- if (line == NULL)
- return (-1);
- number = strsep(&line, " ");
- if (line == NULL)
- return (-1);
- readable = line;
-
- if (strcmp(protocol, "HTTP/1.0") == 0) {
- req->major = 1;
- req->minor = 0;
- } else if (strcmp(protocol, "HTTP/1.1") == 0) {
- req->major = 1;
- req->minor = 1;
- } else {
- event_debug(("%s: bad protocol \"%s\"",
- __func__, protocol));
- return (-1);
- }
-
- req->response_code = atoi(number);
- if (!evhttp_valid_response_code(req->response_code)) {
- event_debug(("%s: bad response code \"%s\"",
- __func__, number));
- return (-1);
- }
-
- if ((req->response_code_line = strdup(readable)) == NULL)
- event_err(1, "%s: strdup", __func__);
-
- return (0);
-}
-
-/* Parse the first line of a HTTP request */
-
-static int
-evhttp_parse_request_line(struct evhttp_request *req, char *line)
-{
- char *method;
- char *uri;
- char *version;
-
- /* Parse the request line */
- method = strsep(&line, " ");
- if (line == NULL)
- return (-1);
- uri = strsep(&line, " ");
- if (line == NULL)
- return (-1);
- version = strsep(&line, " ");
- if (line != NULL)
- return (-1);
-
- /* First line */
- if (strcmp(method, "GET") == 0) {
- req->type = EVHTTP_REQ_GET;
- } else if (strcmp(method, "POST") == 0) {
- req->type = EVHTTP_REQ_POST;
- } else if (strcmp(method, "HEAD") == 0) {
- req->type = EVHTTP_REQ_HEAD;
- } else {
- event_debug(("%s: bad method %s on request %p from %s",
- __func__, method, req, req->remote_host));
- return (-1);
- }
-
- if (strcmp(version, "HTTP/1.0") == 0) {
- req->major = 1;
- req->minor = 0;
- } else if (strcmp(version, "HTTP/1.1") == 0) {
- req->major = 1;
- req->minor = 1;
- } else {
- event_debug(("%s: bad version %s on request %p from %s",
- __func__, version, req, req->remote_host));
- return (-1);
- }
-
- if ((req->uri = strdup(uri)) == NULL) {
- event_debug(("%s: evhttp_decode_uri", __func__));
- return (-1);
- }
-
- /* determine if it's a proxy request */
- if (strlen(req->uri) > 0 && req->uri[0] != '/')
- req->flags |= EVHTTP_PROXY_REQUEST;
-
- return (0);
-}
-
-const char *
-evhttp_find_header(const struct evkeyvalq *headers, const char *key)
-{
- struct evkeyval *header;
-
- TAILQ_FOREACH(header, headers, next) {
- if (strcasecmp(header->key, key) == 0)
- return (header->value);
- }
-
- return (NULL);
-}
-
-void
-evhttp_clear_headers(struct evkeyvalq *headers)
-{
- struct evkeyval *header;
-
- for (header = TAILQ_FIRST(headers);
- header != NULL;
- header = TAILQ_FIRST(headers)) {
- TAILQ_REMOVE(headers, header, next);
- free(header->key);
- free(header->value);
- free(header);
- }
-}
-
-/*
- * Returns 0, if the header was successfully removed.
- * Returns -1, if the header could not be found.
- */
-
-int
-evhttp_remove_header(struct evkeyvalq *headers, const char *key)
-{
- struct evkeyval *header;
-
- TAILQ_FOREACH(header, headers, next) {
- if (strcasecmp(header->key, key) == 0)
- break;
- }
-
- if (header == NULL)
- return (-1);
-
- /* Free and remove the header that we found */
- TAILQ_REMOVE(headers, header, next);
- free(header->key);
- free(header->value);
- free(header);
-
- return (0);
-}
-
-static int
-evhttp_header_is_valid_value(const char *value)
-{
- const char *p = value;
-
- while ((p = strpbrk(p, "\r\n")) != NULL) {
- /* we really expect only one new line */
- p += strspn(p, "\r\n");
- /* we expect a space or tab for continuation */
- if (*p != ' ' && *p != '\t')
- return (0);
- }
- return (1);
-}
-
-int
-evhttp_add_header(struct evkeyvalq *headers,
- const char *key, const char *value)
-{
- event_debug(("%s: key: %s val: %s\n", __func__, key, value));
-
- if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
- /* drop illegal headers */
- event_debug(("%s: dropping illegal header key\n", __func__));
- return (-1);
- }
-
- if (!evhttp_header_is_valid_value(value)) {
- event_debug(("%s: dropping illegal header value\n", __func__));
- return (-1);
- }
-
- return (evhttp_add_header_internal(headers, key, value));
-}
-
-static int
-evhttp_add_header_internal(struct evkeyvalq *headers,
- const char *key, const char *value)
-{
- struct evkeyval *header = calloc(1, sizeof(struct evkeyval));
- if (header == NULL) {
- event_warn("%s: calloc", __func__);
- return (-1);
- }
- if ((header->key = strdup(key)) == NULL) {
- free(header);
- event_warn("%s: strdup", __func__);
- return (-1);
- }
- if ((header->value = strdup(value)) == NULL) {
- free(header->key);
- free(header);
- event_warn("%s: strdup", __func__);
- return (-1);
- }
-
- TAILQ_INSERT_TAIL(headers, header, next);
-
- return (0);
-}
-
-/*
- * Parses header lines from a request or a response into the specified
- * request object given an event buffer.
- *
- * Returns
- * DATA_CORRUPTED on error
- * MORE_DATA_EXPECTED when we need to read more headers
- * ALL_DATA_READ when all headers have been read.
- */
-
-enum message_read_status
-evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer)
-{
- char *line;
- enum message_read_status status = ALL_DATA_READ;
-
- line = evbuffer_readline(buffer);
- if (line == NULL)
- return (MORE_DATA_EXPECTED);
-
- switch (req->kind) {
- case EVHTTP_REQUEST:
- if (evhttp_parse_request_line(req, line) == -1)
- status = DATA_CORRUPTED;
- break;
- case EVHTTP_RESPONSE:
- if (evhttp_parse_response_line(req, line) == -1)
- status = DATA_CORRUPTED;
- break;
- default:
- status = DATA_CORRUPTED;
- }
-
- free(line);
- return (status);
-}
-
-static int
-evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line)
-{
- struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
- char *newval;
- size_t old_len, line_len;
-
- if (header == NULL)
- return (-1);
-
- old_len = strlen(header->value);
- line_len = strlen(line);
-
- newval = realloc(header->value, old_len + line_len + 1);
- if (newval == NULL)
- return (-1);
-
- memcpy(newval + old_len, line, line_len + 1);
- header->value = newval;
-
- return (0);
-}
-
-enum message_read_status
-evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
-{
- char *line;
- enum message_read_status status = MORE_DATA_EXPECTED;
-
- struct evkeyvalq* headers = req->input_headers;
- while ((line = evbuffer_readline(buffer))
- != NULL) {
- char *skey, *svalue;
-
- if (*line == '\0') { /* Last header - Done */
- status = ALL_DATA_READ;
- free(line);
- break;
- }
-
- /* Check if this is a continuation line */
- if (*line == ' ' || *line == '\t') {
- if (evhttp_append_to_last_header(headers, line) == -1)
- goto error;
- free(line);
- continue;
- }
-
- /* Processing of header lines */
- svalue = line;
- skey = strsep(&svalue, ":");
- if (svalue == NULL)
- goto error;
-
- svalue += strspn(svalue, " ");
-
- if (evhttp_add_header(headers, skey, svalue) == -1)
- goto error;
-
- free(line);
- }
-
- return (status);
-
- error:
- free(line);
- return (DATA_CORRUPTED);
-}
-
-static int
-evhttp_get_body_length(struct evhttp_request *req)
-{
- struct evkeyvalq *headers = req->input_headers;
- const char *content_length;
- const char *connection;
-
- content_length = evhttp_find_header(headers, "Content-Length");
- connection = evhttp_find_header(headers, "Connection");
-
- if (content_length == NULL && connection == NULL)
- req->ntoread = -1;
- else if (content_length == NULL &&
- strcasecmp(connection, "Close") != 0) {
- /* Bad combination, we don't know when it will end */
- event_warnx("%s: we got no content length, but the "
- "server wants to keep the connection open: %s.",
- __func__, connection);
- return (-1);
- } else if (content_length == NULL) {
- req->ntoread = -1;
- } else {
- char *endp;
- ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
- if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
- event_debug(("%s: illegal content length: %s",
- __func__, content_length));
- return (-1);
- }
- req->ntoread = ntoread;
- }
-
- event_debug(("%s: bytes to read: %lld (in buffer %ld)\n",
- __func__, req->ntoread,
- EVBUFFER_LENGTH(req->evcon->input_buffer)));
-
- return (0);
-}
-
-static void
-evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- const char *xfer_enc;
-
- /* If this is a request without a body, then we are done */
- if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
- evhttp_connection_done(evcon);
- return;
- }
- evcon->state = EVCON_READING_BODY;
- xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
- if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) {
- req->chunked = 1;
- req->ntoread = -1;
- } else {
- if (evhttp_get_body_length(req) == -1) {
- evhttp_connection_fail(evcon,
- EVCON_HTTP_INVALID_HEADER);
- return;
- }
- }
- evhttp_read_body(evcon, req);
-}
-
-static void
-evhttp_read_firstline(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- enum message_read_status res;
-
- res = evhttp_parse_firstline(req, evcon->input_buffer);
- if (res == DATA_CORRUPTED) {
- /* Error while reading, terminate */
- event_debug(("%s: bad header lines on %d\n",
- __func__, evcon->fd));
- evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
- return;
- } else if (res == MORE_DATA_EXPECTED) {
- /* Need more header lines */
- evhttp_add_event(&evcon->ev,
- evcon->timeout, HTTP_READ_TIMEOUT);
- return;
- }
-
- evcon->state = EVCON_READING_HEADERS;
- evhttp_read_header(evcon, req);
-}
-
-static void
-evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- enum message_read_status res;
- int fd = evcon->fd;
-
- res = evhttp_parse_headers(req, evcon->input_buffer);
- if (res == DATA_CORRUPTED) {
- /* Error while reading, terminate */
- event_debug(("%s: bad header lines on %d\n", __func__, fd));
- evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
- return;
- } else if (res == MORE_DATA_EXPECTED) {
- /* Need more header lines */
- evhttp_add_event(&evcon->ev,
- evcon->timeout, HTTP_READ_TIMEOUT);
- return;
- }
-
- /* Done reading headers, do the real work */
- switch (req->kind) {
- case EVHTTP_REQUEST:
- event_debug(("%s: checking for post data on %d\n",
- __func__, fd));
- evhttp_get_body(evcon, req);
- break;
-
- case EVHTTP_RESPONSE:
- if (req->response_code == HTTP_NOCONTENT ||
- req->response_code == HTTP_NOTMODIFIED ||
- (req->response_code >= 100 && req->response_code < 200)) {
- event_debug(("%s: skipping body for code %d\n",
- __func__, req->response_code));
- evhttp_connection_done(evcon);
- } else {
- event_debug(("%s: start of read body for %s on %d\n",
- __func__, req->remote_host, fd));
- evhttp_get_body(evcon, req);
- }
- break;
-
- default:
- event_warnx("%s: bad header on %d", __func__, fd);
- evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
- break;
- }
-}
-
-/*
- * Creates a TCP connection to the specified port and executes a callback
- * when finished. Failure or sucess is indicate by the passed connection
- * object.
- *
- * Although this interface accepts a hostname, it is intended to take
- * only numeric hostnames so that non-blocking DNS resolution can
- * happen elsewhere.
- */
-
-struct evhttp_connection *
-evhttp_connection_new(const char *address, unsigned short port)
-{
- struct evhttp_connection *evcon = NULL;
-
- event_debug(("Attempting connection to %s:%d\n", address, port));
-
- if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) {
- event_warn("%s: calloc failed", __func__);
- goto error;
- }
-
- evcon->fd = -1;
- evcon->port = port;
-
- evcon->timeout = -1;
- evcon->retry_cnt = evcon->retry_max = 0;
-
- if ((evcon->address = strdup(address)) == NULL) {
- event_warn("%s: strdup failed", __func__);
- goto error;
- }
-
- if ((evcon->input_buffer = evbuffer_new()) == NULL) {
- event_warn("%s: evbuffer_new failed", __func__);
- goto error;
- }
-
- if ((evcon->output_buffer = evbuffer_new()) == NULL) {
- event_warn("%s: evbuffer_new failed", __func__);
- goto error;
- }
-
- evcon->state = EVCON_DISCONNECTED;
- TAILQ_INIT(&evcon->requests);
-
- return (evcon);
-
- error:
- if (evcon != NULL)
- evhttp_connection_free(evcon);
- return (NULL);
-}
-
-void evhttp_connection_set_base(struct evhttp_connection *evcon,
- struct event_base *base)
-{
- assert(evcon->base == NULL);
- assert(evcon->state == EVCON_DISCONNECTED);
- evcon->base = base;
-}
-
-void
-evhttp_connection_set_timeout(struct evhttp_connection *evcon,
- int timeout_in_secs)
-{
- evcon->timeout = timeout_in_secs;
-}
-
-void
-evhttp_connection_set_retries(struct evhttp_connection *evcon,
- int retry_max)
-{
- evcon->retry_max = retry_max;
-}
-
-void
-evhttp_connection_set_closecb(struct evhttp_connection *evcon,
- void (*cb)(struct evhttp_connection *, void *), void *cbarg)
-{
- evcon->closecb = cb;
- evcon->closecb_arg = cbarg;
-}
-
-void
-evhttp_connection_get_peer(struct evhttp_connection *evcon,
- char **address, u_short *port)
-{
- *address = evcon->address;
- *port = evcon->port;
-}
-
-int
-evhttp_connection_connect(struct evhttp_connection *evcon)
-{
- if (evcon->state == EVCON_CONNECTING)
- return (0);
-
- evhttp_connection_reset(evcon);
-
- assert(!(evcon->flags & EVHTTP_CON_INCOMING));
- evcon->flags |= EVHTTP_CON_OUTGOING;
-
- evcon->fd = bind_socket(
- evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
- if (evcon->fd == -1) {
- event_debug(("%s: failed to bind to \"%s\"",
- __func__, evcon->bind_address));
- return (-1);
- }
-
- if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) {
- EVUTIL_CLOSESOCKET(evcon->fd); evcon->fd = -1;
- return (-1);
- }
-
- /* Set up a callback for successful connection setup */
- event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
- EVHTTP_BASE_SET(evcon, &evcon->ev);
- evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_CONNECT_TIMEOUT);
-
- evcon->state = EVCON_CONNECTING;
-
- return (0);
-}
-
-/*
- * Starts an HTTP request on the provided evhttp_connection object.
- * If the connection object is not connected to the web server already,
- * this will start the connection.
- */
-
-int
-evhttp_make_request(struct evhttp_connection *evcon,
- struct evhttp_request *req,
- enum evhttp_cmd_type type, const char *uri)
-{
- /* We are making a request */
- req->kind = EVHTTP_REQUEST;
- req->type = type;
- if (req->uri != NULL)
- free(req->uri);
- if ((req->uri = strdup(uri)) == NULL)
- event_err(1, "%s: strdup", __func__);
-
- /* Set the protocol version if it is not supplied */
- if (!req->major && !req->minor) {
- req->major = 1;
- req->minor = 1;
- }
-
- assert(req->evcon == NULL);
- req->evcon = evcon;
- assert(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
-
- TAILQ_INSERT_TAIL(&evcon->requests, req, next);
-
- /* If the connection object is not connected; make it so */
- if (!evhttp_connected(evcon))
- return (evhttp_connection_connect(evcon));
-
- /*
- * If it's connected already and we are the first in the queue,
- * then we can dispatch this request immediately. Otherwise, it
- * will be dispatched once the pending requests are completed.
- */
- if (TAILQ_FIRST(&evcon->requests) == req)
- evhttp_request_dispatch(evcon);
-
- return (0);
-}
-
-/*
- * Reads data from file descriptor into request structure
- * Request structure needs to be set up correctly.
- */
-
-void
-evhttp_start_read(struct evhttp_connection *evcon)
-{
- /* Set up an event to read the headers */
- if (event_initialized(&evcon->ev))
- event_del(&evcon->ev);
- event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
- EVHTTP_BASE_SET(evcon, &evcon->ev);
-
- evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
- evcon->state = EVCON_READING_FIRSTLINE;
-}
-
-static void
-evhttp_send_done(struct evhttp_connection *evcon, void *arg)
-{
- int need_close;
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
- TAILQ_REMOVE(&evcon->requests, req, next);
-
- /* delete possible close detection events */
- evhttp_connection_stop_detectclose(evcon);
-
- need_close =
- (req->minor == 0 &&
- !evhttp_is_connection_keepalive(req->input_headers))||
- evhttp_is_connection_close(req->flags, req->input_headers) ||
- evhttp_is_connection_close(req->flags, req->output_headers);
-
- assert(req->flags & EVHTTP_REQ_OWN_CONNECTION);
- evhttp_request_free(req);
-
- if (need_close) {
- evhttp_connection_free(evcon);
- return;
- }
-
- /* we have a persistent connection; try to accept another request. */
- if (evhttp_associate_new_request_with_connection(evcon) == -1)
- evhttp_connection_free(evcon);
-}
-
-/*
- * Returns an error page.
- */
-
-void
-evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
-{
-#define ERR_FORMAT "<HTML><HEAD>\n" \
- "<TITLE>%d %s</TITLE>\n" \
- "</HEAD><BODY>\n" \
- "<H1>Method Not Implemented</H1>\n" \
- "Invalid method in request<P>\n" \
- "</BODY></HTML>\n"
-
- struct evbuffer *buf = evbuffer_new();
-
- /* close the connection on error */
- evhttp_add_header(req->output_headers, "Connection", "close");
-
- evhttp_response_code(req, error, reason);
-
- evbuffer_add_printf(buf, ERR_FORMAT, error, reason);
-
- evhttp_send_page(req, buf);
-
- evbuffer_free(buf);
-#undef ERR_FORMAT
-}
-
-/* Requires that headers and response code are already set up */
-
-static inline void
-evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
-{
- struct evhttp_connection *evcon = req->evcon;
-
- assert(TAILQ_FIRST(&evcon->requests) == req);
-
- /* xxx: not sure if we really should expose the data buffer this way */
- if (databuf != NULL)
- evbuffer_add_buffer(req->output_buffer, databuf);
-
- /* Adds headers to the response */
- evhttp_make_header(evcon, req);
-
- evhttp_write_buffer(evcon, evhttp_send_done, NULL);
-}
-
-void
-evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
- struct evbuffer *databuf)
-{
- evhttp_response_code(req, code, reason);
-
- evhttp_send(req, databuf);
-}
-
-void
-evhttp_send_reply_start(struct evhttp_request *req, int code,
- const char *reason)
-{
- evhttp_response_code(req, code, reason);
- if (req->major == 1 && req->minor == 1) {
- /* use chunked encoding for HTTP/1.1 */
- evhttp_add_header(req->output_headers, "Transfer-Encoding",
- "chunked");
- req->chunked = 1;
- }
- evhttp_make_header(req->evcon, req);
- evhttp_write_buffer(req->evcon, NULL, NULL);
-}
-
-void
-evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
-{
- if (req->chunked) {
- evbuffer_add_printf(req->evcon->output_buffer, "%x\r\n",
- (unsigned)EVBUFFER_LENGTH(databuf));
- }
- evbuffer_add_buffer(req->evcon->output_buffer, databuf);
- if (req->chunked) {
- evbuffer_add(req->evcon->output_buffer, "\r\n", 2);
- }
- evhttp_write_buffer(req->evcon, NULL, NULL);
-}
-
-void
-evhttp_send_reply_end(struct evhttp_request *req)
-{
- struct evhttp_connection *evcon = req->evcon;
-
- if (req->chunked) {
- evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
- evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
- req->chunked = 0;
- } else if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) {
- /* let the connection know that we are done with the request */
- evhttp_send_done(evcon, NULL);
- } else {
- /* make the callback execute after all data has been written */
- evcon->cb = evhttp_send_done;
- evcon->cb_arg = NULL;
- }
-}
-
-void
-evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
-{
- req->kind = EVHTTP_RESPONSE;
- req->response_code = code;
- if (req->response_code_line != NULL)
- free(req->response_code_line);
- req->response_code_line = strdup(reason);
-}
-
-void
-evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
-{
- if (!req->major || !req->minor) {
- req->major = 1;
- req->minor = 1;
- }
-
- if (req->kind != EVHTTP_RESPONSE)
- evhttp_response_code(req, 200, "OK");
-
- evhttp_clear_headers(req->output_headers);
- evhttp_add_header(req->output_headers, "Content-Type", "text/html");
- evhttp_add_header(req->output_headers, "Connection", "close");
-
- evhttp_send(req, databuf);
-}
-
-static const char uri_chars[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
- /* 64 */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
- /* 128 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 192 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-/*
- * Helper functions to encode/decode a URI.
- * The returned string must be freed by the caller.
- */
-char *
-evhttp_encode_uri(const char *uri)
-{
- struct evbuffer *buf = evbuffer_new();
- char *p;
-
- for (p = (char *)uri; *p != '\0'; p++) {
- if (uri_chars[(u_char)(*p)]) {
- evbuffer_add(buf, p, 1);
- } else {
- evbuffer_add_printf(buf, "%%%02X", (u_char)(*p));
- }
- }
- evbuffer_add(buf, "", 1);
- p = strdup((char *)EVBUFFER_DATA(buf));
- evbuffer_free(buf);
-
- return (p);
-}
-
-/*
- * @param always_decode_plus: when true we transform plus to space even
- * if we have not seen a ?.
- */
-static int
-evhttp_decode_uri_internal(
- const char *uri, size_t length, char *ret, int always_decode_plus)
-{
- char c;
- int i, j, in_query = always_decode_plus;
-
- for (i = j = 0; uri[i] != '\0'; i++) {
- c = uri[i];
- if (c == '?') {
- in_query = 1;
- } else if (c == '+' && in_query) {
- c = ' ';
- } else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
- isxdigit((unsigned char)uri[i+2])) {
- char tmp[] = { uri[i+1], uri[i+2], '\0' };
- c = (char)strtol(tmp, NULL, 16);
- i += 2;
- }
- ret[j++] = c;
- }
- ret[j] = '\0';
-
- return (j);
-}
-
-char *
-evhttp_decode_uri(const char *uri)
-{
- char *ret;
-
- if ((ret = malloc(strlen(uri) + 1)) == NULL)
- event_err(1, "%s: malloc(%lu)", __func__,
- (unsigned long)(strlen(uri) + 1));
-
- evhttp_decode_uri_internal(uri, strlen(uri),
- ret, 0 /*always_decode_plus*/);
-
- return (ret);
-}
-
-/*
- * Helper function to parse out arguments in a query.
- * The arguments are separated by key and value.
- */
-
-void
-evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
-{
- char *line;
- char *argument;
- char *p;
-
- TAILQ_INIT(headers);
-
- /* No arguments - we are done */
- if (strchr(uri, '?') == NULL)
- return;
-
- if ((line = strdup(uri)) == NULL)
- event_err(1, "%s: strdup", __func__);
-
-
- argument = line;
-
- /* We already know that there has to be a ? */
- strsep(&argument, "?");
-
- p = argument;
- while (p != NULL && *p != '\0') {
- char *key, *value, *decoded_value;
- argument = strsep(&p, "&");
-
- value = argument;
- key = strsep(&value, "=");
- if (value == NULL)
- goto error;
-
- if ((decoded_value = malloc(strlen(value) + 1)) == NULL)
- event_err(1, "%s: malloc", __func__);
-
- evhttp_decode_uri_internal(value, strlen(value),
- decoded_value, 1 /*always_decode_plus*/);
- event_debug(("Query Param: %s -> %s\n", key, decoded_value));
- evhttp_add_header_internal(headers, key, decoded_value);
- free(decoded_value);
- }
-
- error:
- free(line);
-}
-
-static struct evhttp_cb *
-evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
-{
- struct evhttp_cb *cb;
- size_t offset = 0;
-
- /* Test for different URLs */
- char *p = strchr(req->uri, '?');
- if (p != NULL)
- offset = (size_t)(p - req->uri);
-
- TAILQ_FOREACH(cb, callbacks, next) {
- int res = 0;
- if (p == NULL) {
- res = strcmp(cb->what, req->uri) == 0;
- } else {
- res = ((strncmp(cb->what, req->uri, offset) == 0) &&
- (cb->what[offset] == '\0'));
- }
-
- if (res)
- return (cb);
- }
-
- return (NULL);
-}
-
-static void
-evhttp_handle_request(struct evhttp_request *req, void *arg)
-{
- struct evhttp *http = arg;
- struct evhttp_cb *cb = NULL;
-
- if (req->uri == NULL) {
- evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
- return;
- }
-
- if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
- (*cb->cb)(req, cb->cbarg);
- return;
- }
-
- /* Generic call back */
- if (http->gencb) {
- (*http->gencb)(req, http->gencbarg);
- return;
- } else {
- /* We need to send a 404 here */
-#define ERR_FORMAT "<html><head>" \
- "<title>404 Not Found</title>" \
- "</head><body>" \
- "<h1>Not Found</h1>" \
- "<p>The requested URL %s was not found on this server.</p>"\
- "</body></html>\n"
-
- char *escaped_html = evhttp_htmlescape(req->uri);
- struct evbuffer *buf = evbuffer_new();
-
- evhttp_response_code(req, HTTP_NOTFOUND, "Not Found");
-
- evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
-
- free(escaped_html);
-
- evhttp_send_page(req, buf);
-
- evbuffer_free(buf);
-#undef ERR_FORMAT
- }
-}
-
-static void
-accept_socket(int fd, short what, void *arg)
-{
- struct evhttp *http = arg;
- struct sockaddr_storage ss;
- socklen_t addrlen = sizeof(ss);
- int nfd;
-
- if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
- if (errno != EAGAIN && errno != EINTR)
- event_warn("%s: bad accept", __func__);
- return;
- }
- if (evutil_make_socket_nonblocking(nfd) < 0)
- return;
-
- evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
-}
-
-int
-evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
-{
- int fd;
- int res;
-
- if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
- return (-1);
-
- if (listen(fd, 128) == -1) {
- event_warn("%s: listen", __func__);
- EVUTIL_CLOSESOCKET(fd);
- return (-1);
- }
-
- res = evhttp_accept_socket(http, fd);
-
- if (res != -1)
- event_debug(("Bound to port %d - Awaiting connections ... ",
- port));
-
- return (res);
-}
-
-int
-evhttp_accept_socket(struct evhttp *http, int fd)
-{
- struct evhttp_bound_socket *bound;
- struct event *ev;
- int res;
-
- bound = malloc(sizeof(struct evhttp_bound_socket));
- if (bound == NULL)
- return (-1);
-
- ev = &bound->bind_ev;
-
- /* Schedule the socket for accepting */
- event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
- EVHTTP_BASE_SET(http, ev);
-
- res = event_add(ev, NULL);
-
- if (res == -1) {
- free(bound);
- return (-1);
- }
-
- TAILQ_INSERT_TAIL(&http->sockets, bound, next);
-
- return (0);
-}
-
-static struct evhttp*
-evhttp_new_object(void)
-{
- struct evhttp *http = NULL;
-
- if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
- event_warn("%s: calloc", __func__);
- return (NULL);
- }
-
- http->timeout = -1;
-
- TAILQ_INIT(&http->sockets);
- TAILQ_INIT(&http->callbacks);
- TAILQ_INIT(&http->connections);
-
- return (http);
-}
-
-struct evhttp *
-evhttp_new(struct event_base *base)
-{
- struct evhttp *http = evhttp_new_object();
-
- http->base = base;
-
- return (http);
-}
-
-/*
- * Start a web server on the specified address and port.
- */
-
-struct evhttp *
-evhttp_start(const char *address, u_short port)
-{
- struct evhttp *http = evhttp_new_object();
-
- if (evhttp_bind_socket(http, address, port) == -1) {
- free(http);
- return (NULL);
- }
-
- return (http);
-}
-
-void
-evhttp_free(struct evhttp* http)
-{
- struct evhttp_cb *http_cb;
- struct evhttp_connection *evcon;
- struct evhttp_bound_socket *bound;
- int fd;
-
- /* Remove the accepting part */
- while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
- TAILQ_REMOVE(&http->sockets, bound, next);
-
- fd = bound->bind_ev.ev_fd;
- event_del(&bound->bind_ev);
- EVUTIL_CLOSESOCKET(fd);
-
- free(bound);
- }
-
- while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
- /* evhttp_connection_free removes the connection */
- evhttp_connection_free(evcon);
- }
-
- while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
- TAILQ_REMOVE(&http->callbacks, http_cb, next);
- free(http_cb->what);
- free(http_cb);
- }
-
- free(http);
-}
-
-void
-evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
-{
- http->timeout = timeout_in_secs;
-}
-
-void
-evhttp_set_cb(struct evhttp *http, const char *uri,
- void (*cb)(struct evhttp_request *, void *), void *cbarg)
-{
- struct evhttp_cb *http_cb;
-
- if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL)
- event_err(1, "%s: calloc", __func__);
-
- http_cb->what = strdup(uri);
- http_cb->cb = cb;
- http_cb->cbarg = cbarg;
-
- TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
-}
-
-int
-evhttp_del_cb(struct evhttp *http, const char *uri)
-{
- struct evhttp_cb *http_cb;
-
- TAILQ_FOREACH(http_cb, &http->callbacks, next) {
- if (strcmp(http_cb->what, uri) == 0)
- break;
- }
- if (http_cb == NULL)
- return (-1);
-
- TAILQ_REMOVE(&http->callbacks, http_cb, next);
- free(http_cb->what);
- free(http_cb);
-
- return (0);
-}
-
-void
-evhttp_set_gencb(struct evhttp *http,
- void (*cb)(struct evhttp_request *, void *), void *cbarg)
-{
- http->gencb = cb;
- http->gencbarg = cbarg;
-}
-
-/*
- * Request related functions
- */
-
-struct evhttp_request *
-evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
-{
- struct evhttp_request *req = NULL;
-
- /* Allocate request structure */
- if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) {
- event_warn("%s: calloc", __func__);
- goto error;
- }
-
- req->kind = EVHTTP_RESPONSE;
- req->input_headers = calloc(1, sizeof(struct evkeyvalq));
- if (req->input_headers == NULL) {
- event_warn("%s: calloc", __func__);
- goto error;
- }
- TAILQ_INIT(req->input_headers);
-
- req->output_headers = calloc(1, sizeof(struct evkeyvalq));
- if (req->output_headers == NULL) {
- event_warn("%s: calloc", __func__);
- goto error;
- }
- TAILQ_INIT(req->output_headers);
-
- if ((req->input_buffer = evbuffer_new()) == NULL) {
- event_warn("%s: evbuffer_new", __func__);
- goto error;
- }
-
- if ((req->output_buffer = evbuffer_new()) == NULL) {
- event_warn("%s: evbuffer_new", __func__);
- goto error;
- }
-
- req->cb = cb;
- req->cb_arg = arg;
-
- return (req);
-
- error:
- if (req != NULL)
- evhttp_request_free(req);
- return (NULL);
-}
-
-void
-evhttp_request_free(struct evhttp_request *req)
-{
- if (req->remote_host != NULL)
- free(req->remote_host);
- if (req->uri != NULL)
- free(req->uri);
- if (req->response_code_line != NULL)
- free(req->response_code_line);
-
- evhttp_clear_headers(req->input_headers);
- free(req->input_headers);
-
- evhttp_clear_headers(req->output_headers);
- free(req->output_headers);
-
- if (req->input_buffer != NULL)
- evbuffer_free(req->input_buffer);
-
- if (req->output_buffer != NULL)
- evbuffer_free(req->output_buffer);
-
- free(req);
-}
-
-void
-evhttp_request_set_chunked_cb(struct evhttp_request *req,
- void (*cb)(struct evhttp_request *, void *))
-{
- req->chunk_cb = cb;
-}
-
-/*
- * Allows for inspection of the request URI
- */
-
-const char *
-evhttp_request_uri(struct evhttp_request *req) {
- if (req->uri == NULL)
- event_debug(("%s: request %p has no uri\n", __func__, req));
- return (req->uri);
-}
-
-/*
- * Takes a file descriptor to read a request from.
- * The callback is executed once the whole request has been read.
- */
-
-static struct evhttp_connection*
-evhttp_get_request_connection(
- struct evhttp* http,
- int fd, struct sockaddr *sa, socklen_t salen)
-{
- struct evhttp_connection *evcon;
- char *hostname = NULL, *portname = NULL;
-
- name_from_addr(sa, salen, &hostname, &portname);
- if (hostname == NULL || portname == NULL) {
- if (hostname) free(hostname);
- if (portname) free(portname);
- return (NULL);
- }
-
- event_debug(("%s: new request from %s:%s on %d\n",
- __func__, hostname, portname, fd));
-
- /* we need a connection object to put the http request on */
- evcon = evhttp_connection_new(hostname, atoi(portname));
- free(hostname);
- free(portname);
- if (evcon == NULL)
- return (NULL);
-
- /* associate the base if we have one*/
- evhttp_connection_set_base(evcon, http->base);
-
- evcon->flags |= EVHTTP_CON_INCOMING;
- evcon->state = EVCON_READING_FIRSTLINE;
-
- evcon->fd = fd;
-
- return (evcon);
-}
-
-static int
-evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
-{
- struct evhttp *http = evcon->http_server;
- struct evhttp_request *req;
- if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
- return (-1);
-
- req->evcon = evcon; /* the request ends up owning the connection */
- req->flags |= EVHTTP_REQ_OWN_CONNECTION;
-
- TAILQ_INSERT_TAIL(&evcon->requests, req, next);
-
- req->kind = EVHTTP_REQUEST;
-
- if ((req->remote_host = strdup(evcon->address)) == NULL)
- event_err(1, "%s: strdup", __func__);
- req->remote_port = evcon->port;
-
- evhttp_start_read(evcon);
-
- return (0);
-}
-
-void
-evhttp_get_request(struct evhttp *http, int fd,
- struct sockaddr *sa, socklen_t salen)
-{
- struct evhttp_connection *evcon;
-
- evcon = evhttp_get_request_connection(http, fd, sa, salen);
- if (evcon == NULL)
- return;
-
- /* the timeout can be used by the server to close idle connections */
- if (http->timeout != -1)
- evhttp_connection_set_timeout(evcon, http->timeout);
-
- /*
- * if we want to accept more than one request on a connection,
- * we need to know which http server it belongs to.
- */
- evcon->http_server = http;
- TAILQ_INSERT_TAIL(&http->connections, evcon, next);
-
- if (evhttp_associate_new_request_with_connection(evcon) == -1)
- evhttp_connection_free(evcon);
-}
-
-
-/*
- * Network helper functions that we do not want to export to the rest of
- * the world.
- */
-#if 0 /* Unused */
-static struct addrinfo *
-addr_from_name(char *address)
-{
-#ifdef HAVE_GETADDRINFO
- struct addrinfo ai, *aitop;
- int ai_result;
-
- memset(&ai, 0, sizeof(ai));
- ai.ai_family = AF_INET;
- ai.ai_socktype = SOCK_RAW;
- ai.ai_flags = 0;
- if ((ai_result = getaddrinfo(address, NULL, &ai, &aitop)) != 0) {
- if ( ai_result == EAI_SYSTEM )
- event_warn("getaddrinfo");
- else
- event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
- }
-
- return (aitop);
-#else
- assert(0);
- return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */
-#endif
-}
-#endif
-
-static void
-name_from_addr(struct sockaddr *sa, socklen_t salen,
- char **phost, char **pport)
-{
- char ntop[NI_MAXHOST];
- char strport[NI_MAXSERV];
- int ni_result;
-
-#ifdef HAVE_GETNAMEINFO
- ni_result = getnameinfo(sa, salen,
- ntop, sizeof(ntop), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV);
-
- if (ni_result != 0) {
- if (ni_result == EAI_SYSTEM)
- event_err(1, "getnameinfo failed");
- else
- event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
- return;
- }
-#else
- ni_result = fake_getnameinfo(sa, salen,
- ntop, sizeof(ntop), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV);
- if (ni_result != 0)
- return;
-#endif
- *phost = strdup(ntop);
- *pport = strdup(strport);
-}
-
-/* Create a non-blocking socket and bind it */
-/* todo: rename this function */
-static int
-bind_socket_ai(struct addrinfo *ai, int reuse)
-{
- int fd, on = 1, r;
- int serrno;
-
- /* Create listen socket */
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- event_warn("socket");
- return (-1);
- }
-
- if (evutil_make_socket_nonblocking(fd) < 0)
- goto out;
-
- if (fcntl(fd, F_SETFD, 1) == -1) {
- event_warn("fcntl(F_SETFD)");
- goto out;
- }
-
- setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
- if (reuse) {
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
- (void *)&on, sizeof(on));
- }
-
- if (ai != NULL) {
- r = bind(fd, ai->ai_addr, ai->ai_addrlen);
- if (r == -1)
- goto out;
- }
-
- return (fd);
-
- out:
- serrno = EVUTIL_SOCKET_ERROR();
- EVUTIL_CLOSESOCKET(fd);
- EVUTIL_SET_SOCKET_ERROR(serrno);
- return (-1);
-}
-
-static struct addrinfo *
-make_addrinfo(const char *address, u_short port)
-{
- struct addrinfo *aitop = NULL;
-
-#ifdef HAVE_GETADDRINFO
- struct addrinfo ai;
- char strport[NI_MAXSERV];
- int ai_result;
-
- memset(&ai, 0, sizeof(ai));
- ai.ai_family = AF_INET;
- ai.ai_socktype = SOCK_STREAM;
- ai.ai_flags = AI_PASSIVE; /* turn NULL host name into INADDR_ANY */
- evutil_snprintf(strport, sizeof(strport), "%d", port);
- if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
- if ( ai_result == EAI_SYSTEM )
- event_warn("getaddrinfo");
- else
- event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
- return (NULL);
- }
-#else
- static int cur;
- static struct addrinfo ai[2]; /* We will be returning the address of some of this memory so it has to last even after this call. */
- if (++cur == 2) cur = 0; /* allow calling this function twice */
-
- if (fake_getaddrinfo(address, &ai[cur]) < 0) {
- event_warn("fake_getaddrinfo");
- return (NULL);
- }
- aitop = &ai[cur];
- ((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port);
-#endif
-
- return (aitop);
-}
-
-static int
-bind_socket(const char *address, u_short port, int reuse)
-{
- int fd;
- struct addrinfo *aitop = NULL;
-
- /* just create an unbound socket */
- if (address == NULL && port == 0)
- return bind_socket_ai(NULL, 0);
-
- aitop = make_addrinfo(address, port);
-
- if (aitop == NULL)
- return (-1);
-
- fd = bind_socket_ai(aitop, reuse);
-
-#ifdef HAVE_GETADDRINFO
- freeaddrinfo(aitop);
-#else
- fake_freeaddrinfo(aitop);
-#endif
-
- return (fd);
-}
-
-static int
-socket_connect(int fd, const char *address, unsigned short port)
-{
- struct addrinfo *ai = make_addrinfo(address, port);
- int res = -1;
-
- if (ai == NULL) {
- event_debug(("%s: make_addrinfo: \"%s:%d\"",
- __func__, address, port));
- return (-1);
- }
-
- if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
- if (errno != EINPROGRESS) {
- goto out;
- }
- }
-
- /* everything is fine */
- res = 0;
-
-out:
-#ifdef HAVE_GETADDRINFO
- freeaddrinfo(ai);
-#else
- fake_freeaddrinfo(ai);
-#endif
-
- return (res);
-}
diff --git a/lib/libevent/kqueue.c b/lib/libevent/kqueue.c
deleted file mode 100644
index 6703a7a7a10..00000000000
--- a/lib/libevent/kqueue.c
+++ /dev/null
@@ -1,422 +0,0 @@
-/* $NetBSD: kqueue.c,v 1.7 2009/07/08 21:23:53 tls Exp $ */
-/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
-
-/*
- * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#else
-#include <sys/_time.h>
-#endif
-#include <sys/queue.h>
-#include <sys/event.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <assert.h>
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-
-#define PTR_TO_UDATA(x) ((intptr_t)(x))
-
-#include "event.h"
-#include "event-internal.h"
-#include "log.h"
-
-#define EVLIST_X_KQINKERNEL 0x1000
-
-#define NEVENT 64
-
-struct kqop {
- struct kevent *changes;
- int nchanges;
- struct kevent *events;
- struct event_list evsigevents[NSIG];
- int nevents;
- int kq;
- pid_t pid;
-};
-
-static void *kq_init (struct event_base *);
-static int kq_add (void *, struct event *);
-static int kq_del (void *, struct event *);
-static int kq_dispatch (struct event_base *, void *, struct timeval *);
-static int kq_insert (struct kqop *, struct kevent *);
-static void kq_dealloc (struct event_base *, void *);
-
-const struct eventop kqops = {
- "kqueue",
- kq_init,
- kq_add,
- kq_del,
- kq_dispatch,
- kq_dealloc,
- 1 /* need reinit */
-};
-
-static void *
-kq_init(struct event_base *base)
-{
- int i, kq;
- struct kqop *kqueueop;
-
- /* Disable kqueue when this environment variable is set */
- if (getenv("EVENT_NOKQUEUE"))
- return (NULL);
-
- if (!(kqueueop = calloc(1, sizeof(struct kqop))))
- return (NULL);
-
- /* Initalize the kernel queue */
-
- if ((kq = kqueue()) == -1) {
- event_warn("kqueue");
- free (kqueueop);
- return (NULL);
- }
-
- kqueueop->kq = kq;
-
- kqueueop->pid = getpid();
-
- /* Initalize fields */
- kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
- if (kqueueop->changes == NULL) {
- free (kqueueop);
- return (NULL);
- }
- kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
- if (kqueueop->events == NULL) {
- free (kqueueop->changes);
- free (kqueueop);
- return (NULL);
- }
- kqueueop->nevents = NEVENT;
-
- /* we need to keep track of multiple events per signal */
- for (i = 0; i < NSIG; ++i) {
- TAILQ_INIT(&kqueueop->evsigevents[i]);
- }
-
- return (kqueueop);
-}
-
-static int
-kq_insert(struct kqop *kqop, struct kevent *kev)
-{
- int nevents = kqop->nevents;
-
- if (kqop->nchanges == nevents) {
- struct kevent *newchange;
- struct kevent *newresult;
-
- nevents *= 2;
-
- newchange = realloc(kqop->changes,
- nevents * sizeof(struct kevent));
- if (newchange == NULL) {
- event_warn("%s: malloc", __func__);
- return (-1);
- }
- kqop->changes = newchange;
-
- newresult = realloc(kqop->events,
- nevents * sizeof(struct kevent));
-
- /*
- * If we fail, we don't have to worry about freeing,
- * the next realloc will pick it up.
- */
- if (newresult == NULL) {
- event_warn("%s: malloc", __func__);
- return (-1);
- }
- kqop->events = newresult;
-
- kqop->nevents = nevents;
- }
-
- memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
-
- event_debug(("%s: fd %d %s%s",
- __func__, (int)kev->ident,
- kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
- kev->flags == EV_DELETE ? " (del)" : ""));
-
- return (0);
-}
-
-static void
-kq_sighandler(int sig)
-{
- /* Do nothing here */
-}
-
-static int
-kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
-{
- struct kqop *kqop = arg;
- struct kevent *changes = kqop->changes;
- struct kevent *events = kqop->events;
- struct event *ev;
- struct timespec ts, *ts_p = NULL;
- int i, res;
-
- if (tv != NULL) {
- TIMEVAL_TO_TIMESPEC(tv, &ts);
- ts_p = &ts;
- }
-
- res = kevent(kqop->kq, changes, kqop->nchanges,
- events, kqop->nevents, ts_p);
- kqop->nchanges = 0;
- if (res == -1) {
- if (errno != EINTR) {
- event_warn("kevent");
- return (-1);
- }
-
- return (0);
- }
-
- event_debug(("%s: kevent reports %d", __func__, res));
-
- for (i = 0; i < res; i++) {
- int which = 0;
-
- if (events[i].flags & EV_ERROR) {
- /*
- * Error messages that can happen, when a delete fails.
- * EBADF happens when the file discriptor has been
- * closed,
- * ENOENT when the file discriptor was closed and
- * then reopened.
- * EINVAL for some reasons not understood; EINVAL
- * should not be returned ever; but FreeBSD does :-\
- * An error is also indicated when a callback deletes
- * an event we are still processing. In that case
- * the data field is set to ENOENT.
- */
- if (events[i].data == EBADF ||
- events[i].data == EINVAL ||
- events[i].data == ENOENT)
- continue;
- errno = events[i].data;
- return (-1);
- }
-
- if (events[i].filter == EVFILT_READ) {
- which |= EV_READ;
- } else if (events[i].filter == EVFILT_WRITE) {
- which |= EV_WRITE;
- } else if (events[i].filter == EVFILT_SIGNAL) {
- which |= EV_SIGNAL;
- }
-
- if (!which)
- continue;
-
- if (events[i].filter == EVFILT_SIGNAL) {
- struct event_list *head =
- (struct event_list *)events[i].udata;
- TAILQ_FOREACH(ev, head, ev_signal_next) {
- event_active(ev, which, events[i].data);
- }
- } else {
- ev = (struct event *)events[i].udata;
-
- if (!(ev->ev_events & EV_PERSIST))
- ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
-
- event_active(ev, which, 1);
- }
- }
-
- return (0);
-}
-
-
-static int
-kq_add(void *arg, struct event *ev)
-{
- struct kqop *kqop = arg;
- struct kevent kev;
-
- if (ev->ev_events & EV_SIGNAL) {
- int nsignal = EVENT_SIGNAL(ev);
-
- assert(nsignal >= 0 && nsignal < NSIG);
- if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
- struct timespec timeout = { 0, 0 };
-
- memset(&kev, 0, sizeof(kev));
- kev.ident = nsignal;
- kev.filter = EVFILT_SIGNAL;
- kev.flags = EV_ADD;
- kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
-
- /* Be ready for the signal if it is sent any
- * time between now and the next call to
- * kq_dispatch. */
- if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
- return (-1);
-
- if (_evsignal_set_handler(ev->ev_base, nsignal,
- kq_sighandler) == -1)
- return (-1);
- }
-
- TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
- ev_signal_next);
- ev->ev_flags |= EVLIST_X_KQINKERNEL;
- return (0);
- }
-
- if (ev->ev_events & EV_READ) {
- memset(&kev, 0, sizeof(kev));
- kev.ident = ev->ev_fd;
- kev.filter = EVFILT_READ;
-#ifdef NOTE_EOF
- /* Make it behave like select() and poll() */
- kev.fflags = NOTE_EOF;
-#endif
- kev.flags = EV_ADD;
- if (!(ev->ev_events & EV_PERSIST))
- kev.flags |= EV_ONESHOT;
- kev.udata = PTR_TO_UDATA(ev);
-
- if (kq_insert(kqop, &kev) == -1)
- return (-1);
-
- ev->ev_flags |= EVLIST_X_KQINKERNEL;
- }
-
- if (ev->ev_events & EV_WRITE) {
- memset(&kev, 0, sizeof(kev));
- kev.ident = ev->ev_fd;
- kev.filter = EVFILT_WRITE;
- kev.flags = EV_ADD;
- if (!(ev->ev_events & EV_PERSIST))
- kev.flags |= EV_ONESHOT;
- kev.udata = PTR_TO_UDATA(ev);
-
- if (kq_insert(kqop, &kev) == -1)
- return (-1);
-
- ev->ev_flags |= EVLIST_X_KQINKERNEL;
- }
-
- return (0);
-}
-
-static int
-kq_del(void *arg, struct event *ev)
-{
- struct kqop *kqop = arg;
- struct kevent kev;
-
- if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
- return (0);
-
- if (ev->ev_events & EV_SIGNAL) {
- int nsignal = EVENT_SIGNAL(ev);
- struct timespec timeout = { 0, 0 };
-
- assert(nsignal >= 0 && nsignal < NSIG);
- TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
- if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
- memset(&kev, 0, sizeof(kev));
- kev.ident = nsignal;
- kev.filter = EVFILT_SIGNAL;
- kev.flags = EV_DELETE;
-
- /* Because we insert signal events
- * immediately, we need to delete them
- * immediately, too */
- if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
- return (-1);
-
- if (_evsignal_restore_handler(ev->ev_base,
- nsignal) == -1)
- return (-1);
- }
-
- ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
- return (0);
- }
-
- if (ev->ev_events & EV_READ) {
- memset(&kev, 0, sizeof(kev));
- kev.ident = ev->ev_fd;
- kev.filter = EVFILT_READ;
- kev.flags = EV_DELETE;
-
- if (kq_insert(kqop, &kev) == -1)
- return (-1);
-
- ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
- }
-
- if (ev->ev_events & EV_WRITE) {
- memset(&kev, 0, sizeof(kev));
- kev.ident = ev->ev_fd;
- kev.filter = EVFILT_WRITE;
- kev.flags = EV_DELETE;
-
- if (kq_insert(kqop, &kev) == -1)
- return (-1);
-
- ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
- }
-
- return (0);
-}
-
-static void
-kq_dealloc(struct event_base *base, void *arg)
-{
- struct kqop *kqop = arg;
-
- if (kqop->changes)
- free(kqop->changes);
- if (kqop->events)
- free(kqop->events);
- if (kqop->kq >= 0 && kqop->pid == getpid())
- close(kqop->kq);
- memset(kqop, 0, sizeof(struct kqop));
- free(kqop);
-}
diff --git a/lib/libevent/log.c b/lib/libevent/log.c
deleted file mode 100644
index 3734f620510..00000000000
--- a/lib/libevent/log.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/* $NetBSD: log.c,v 1.3 2009/07/08 21:23:53 tls Exp $ */
-/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
-
-/*
- * log.c
- *
- * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code.
- *
- * Copyright (c) 2005 Nick Mathewson <nickm@freehaven.net>
- *
- * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
- *
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include "event.h"
-#include "evutil.h"
-
-#include "log.h"
-
-static void _warn_helper(int severity, int log_errno, const char *fmt,
- va_list ap);
-static void event_log(int severity, const char *msg);
-
-void
-event_err(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _warn_helper(_EVENT_LOG_ERR, errno, fmt, ap);
- va_end(ap);
- exit(eval);
-}
-
-void
-event_warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _warn_helper(_EVENT_LOG_WARN, errno, fmt, ap);
- va_end(ap);
-}
-
-void
-event_errx(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _warn_helper(_EVENT_LOG_ERR, -1, fmt, ap);
- va_end(ap);
- exit(eval);
-}
-
-void
-event_warnx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _warn_helper(_EVENT_LOG_WARN, -1, fmt, ap);
- va_end(ap);
-}
-
-void
-event_msgx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _warn_helper(_EVENT_LOG_MSG, -1, fmt, ap);
- va_end(ap);
-}
-
-void
-_event_debugx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- _warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap);
- va_end(ap);
-}
-
-static void
-_warn_helper(int severity, int log_errno, const char *fmt, va_list ap)
-{
- char buf[1024];
- size_t len;
-
- if (fmt != NULL)
- evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
- else
- buf[0] = '\0';
-
- if (log_errno >= 0) {
- len = strlen(buf);
- if (len < sizeof(buf) - 3) {
- evutil_snprintf(buf + len, sizeof(buf) - len, ": %s",
- strerror(log_errno));
- }
- }
-
- event_log(severity, buf);
-}
-
-static event_log_cb log_fn = NULL;
-
-void
-event_set_log_callback(event_log_cb cb)
-{
- log_fn = cb;
-}
-
-static void
-event_log(int severity, const char *msg)
-{
- if (log_fn)
- log_fn(severity, msg);
- else {
- const char *severity_str;
- switch (severity) {
- case _EVENT_LOG_DEBUG:
- severity_str = "debug";
- break;
- case _EVENT_LOG_MSG:
- severity_str = "msg";
- break;
- case _EVENT_LOG_WARN:
- severity_str = "warn";
- break;
- case _EVENT_LOG_ERR:
- severity_str = "err";
- break;
- default:
- severity_str = "???";
- break;
- }
- (void)fprintf(stderr, "[%s] %s\n", severity_str, msg);
- }
-}
diff --git a/lib/libevent/log.h b/lib/libevent/log.h
deleted file mode 100644
index d02f9cec0e2..00000000000
--- a/lib/libevent/log.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* $NetBSD: log.h,v 1.2 2008/05/16 20:24:58 peter Exp $ */
-/*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _LOG_H_
-#define _LOG_H_
-
-#ifdef __GNUC__
-#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
-#else
-#define EV_CHECK_FMT(a,b)
-#endif
-
-void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
-void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
-void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
-void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
-void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
-void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2);
-
-#ifdef USE_DEBUG
-#define event_debug(x) _event_debugx x
-#else
-#define event_debug(x) do {;} while (0)
-#endif
-
-#undef EV_CHECK_FMT
-
-#endif
diff --git a/lib/libevent/min_heap.h b/lib/libevent/min_heap.h
deleted file mode 100644
index 53e776773c5..00000000000
--- a/lib/libevent/min_heap.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* $NetBSD: min_heap.h,v 1.2 2009/07/08 21:23:53 tls Exp $ */
-/*
- * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _MIN_HEAP_H_
-#define _MIN_HEAP_H_
-
-#include "event.h"
-#include "evutil.h"
-
-typedef struct min_heap
-{
- struct event** p;
- unsigned n, a;
-} min_heap_t;
-
-static inline void min_heap_ctor(min_heap_t* s);
-static inline void min_heap_dtor(min_heap_t* s);
-static inline void min_heap_elem_init(struct event* e);
-static inline int min_heap_elem_greater(struct event *a, struct event *b);
-static inline int min_heap_empty(min_heap_t* s);
-static inline unsigned min_heap_size(min_heap_t* s);
-static inline struct event* min_heap_top(min_heap_t* s);
-static inline int min_heap_reserve(min_heap_t* s, unsigned n);
-static inline int min_heap_push(min_heap_t* s, struct event* e);
-static inline struct event* min_heap_pop(min_heap_t* s);
-static inline int min_heap_erase(min_heap_t* s, struct event* e);
-static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
-static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
-
-int min_heap_elem_greater(struct event *a, struct event *b)
-{
- return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
-}
-
-void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
-void min_heap_dtor(min_heap_t* s) { free(s->p); }
-void min_heap_elem_init(struct event* e) { e->min_heap_idx = -1; }
-int min_heap_empty(min_heap_t* s) { return 0u == s->n; }
-unsigned min_heap_size(min_heap_t* s) { return s->n; }
-struct event* min_heap_top(min_heap_t* s) { return s->n ? *s->p : 0; }
-
-int min_heap_push(min_heap_t* s, struct event* e)
-{
- if(min_heap_reserve(s, s->n + 1))
- return -1;
- min_heap_shift_up_(s, s->n++, e);
- return 0;
-}
-
-struct event* min_heap_pop(min_heap_t* s)
-{
- if(s->n)
- {
- struct event* e = *s->p;
- min_heap_shift_down_(s, 0u, s->p[--s->n]);
- e->min_heap_idx = -1;
- return e;
- }
- return 0;
-}
-
-int min_heap_erase(min_heap_t* s, struct event* e)
-{
- if(((unsigned int)-1) != e->min_heap_idx)
- {
- struct event *last = s->p[--s->n];
- unsigned parent = (e->min_heap_idx - 1) / 2;
- /* we replace e with the last element in the heap. We might need to
- shift it upward if it is less than its parent, or downward if it is
- greater than one or both its children. Since the children are known
- to be less than the parent, it can't need to shift both up and
- down. */
- if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
- min_heap_shift_up_(s, e->min_heap_idx, last);
- else
- min_heap_shift_down_(s, e->min_heap_idx, last);
- e->min_heap_idx = -1;
- return 0;
- }
- return -1;
-}
-
-int min_heap_reserve(min_heap_t* s, unsigned n)
-{
- if(s->a < n)
- {
- struct event** p;
- unsigned a = s->a ? s->a * 2 : 8;
- if(a < n)
- a = n;
- if(!(p = (struct event**)realloc(s->p, a * sizeof *p)))
- return -1;
- s->p = p;
- s->a = a;
- }
- return 0;
-}
-
-void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
-{
- unsigned parent = (hole_index - 1) / 2;
- while(hole_index && min_heap_elem_greater(s->p[parent], e))
- {
- (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
- hole_index = parent;
- parent = (hole_index - 1) / 2;
- }
- (s->p[hole_index] = e)->min_heap_idx = hole_index;
-}
-
-void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
-{
- unsigned min_child = 2 * (hole_index + 1);
- while(min_child <= s->n)
- {
- min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
- if(!(min_heap_elem_greater(e, s->p[min_child])))
- break;
- (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
- hole_index = min_child;
- min_child = 2 * (hole_index + 1);
- }
- min_heap_shift_up_(s, hole_index, e);
-}
-
-#endif /* _MIN_HEAP_H_ */
diff --git a/lib/libevent/poll.c b/lib/libevent/poll.c
deleted file mode 100644
index f76aa80ea50..00000000000
--- a/lib/libevent/poll.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/* $NetBSD: poll.c,v 1.8 2009/07/08 21:23:53 tls Exp $ */
-/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
-
-/*
- * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#else
-#include <sys/_time.h>
-#endif
-#include <sys/queue.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#ifdef CHECK_INVARIANTS
-#include <assert.h>
-#endif
-
-#include "event.h"
-#include "event-internal.h"
-#include "evsignal.h"
-#include "log.h"
-
-struct pollop {
- int event_count; /* Highest number alloc */
- int nfds; /* Size of event_* */
- int fd_count; /* Size of idxplus1_by_fd */
- struct pollfd *event_set;
- struct event **event_r_back;
- struct event **event_w_back;
- int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
- * that 0 (which is easy to memset) can mean
- * "no entry." */
-};
-
-static void *poll_init (struct event_base *);
-static int poll_add (void *, struct event *);
-static int poll_del (void *, struct event *);
-static int poll_dispatch (struct event_base *, void *, struct timeval *);
-static void poll_dealloc (struct event_base *, void *);
-
-const struct eventop pollops = {
- "poll",
- poll_init,
- poll_add,
- poll_del,
- poll_dispatch,
- poll_dealloc,
- 0
-};
-
-static void *
-poll_init(struct event_base *base)
-{
- struct pollop *pollop;
-
- /* Disable poll when this environment variable is set */
- if (getenv("EVENT_NOPOLL"))
- return (NULL);
-
- if (!(pollop = calloc(1, sizeof(struct pollop))))
- return (NULL);
-
- evsignal_init(base);
-
- return (pollop);
-}
-
-#ifdef CHECK_INVARIANTS
-static void
-poll_check_ok(struct pollop *pop)
-{
- int i, idx;
- struct event *ev;
-
- for (i = 0; i < pop->fd_count; ++i) {
- idx = pop->idxplus1_by_fd[i]-1;
- if (idx < 0)
- continue;
- assert(pop->event_set[idx].fd == i);
- if (pop->event_set[idx].events & POLLIN) {
- ev = pop->event_r_back[idx];
- assert(ev);
- assert(ev->ev_events & EV_READ);
- assert(ev->ev_fd == i);
- }
- if (pop->event_set[idx].events & POLLOUT) {
- ev = pop->event_w_back[idx];
- assert(ev);
- assert(ev->ev_events & EV_WRITE);
- assert(ev->ev_fd == i);
- }
- }
- for (i = 0; i < pop->nfds; ++i) {
- struct pollfd *pfd = &pop->event_set[i];
- assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
- }
-}
-#else
-#define poll_check_ok(pop)
-#endif
-
-static int
-poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
-{
- int res, i, msec = -1, nfds;
- struct pollop *pop = arg;
-
- poll_check_ok(pop);
-
- if (tv != NULL)
- msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
-
- nfds = pop->nfds;
- res = poll(pop->event_set, nfds, msec);
-
- if (res == -1) {
- if (errno != EINTR) {
- event_warn("poll");
- return (-1);
- }
-
- evsignal_process(base);
- return (0);
- } else if (base->sig.evsignal_caught) {
- evsignal_process(base);
- }
-
- event_debug(("%s: poll reports %d", __func__, res));
-
- if (res == 0)
- return (0);
-
- for (i = 0; i < nfds; i++) {
- int what = pop->event_set[i].revents;
- struct event *r_ev = NULL, *w_ev = NULL;
- if (!what)
- continue;
-
- res = 0;
-
- /* If the file gets closed notify */
- if (what & (POLLHUP|POLLERR))
- what |= POLLIN|POLLOUT;
- if (what & POLLIN) {
- res |= EV_READ;
- r_ev = pop->event_r_back[i];
- }
- if (what & POLLOUT) {
- res |= EV_WRITE;
- w_ev = pop->event_w_back[i];
- }
- if (res == 0)
- continue;
-
- if (r_ev && (res & r_ev->ev_events)) {
- event_active(r_ev, res & r_ev->ev_events, 1);
- }
- if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
- event_active(w_ev, res & w_ev->ev_events, 1);
- }
- }
-
- return (0);
-}
-
-static int
-poll_add(void *arg, struct event *ev)
-{
- struct pollop *pop = arg;
- struct pollfd *pfd = NULL;
- int i;
-
- if (ev->ev_events & EV_SIGNAL)
- return (evsignal_add(ev));
- if (!(ev->ev_events & (EV_READ|EV_WRITE)))
- return (0);
-
- poll_check_ok(pop);
- if (pop->nfds + 1 >= pop->event_count) {
- struct pollfd *tmp_event_set;
- struct event **tmp_event_r_back;
- struct event **tmp_event_w_back;
- int tmp_event_count;
-
- if (pop->event_count < 32)
- tmp_event_count = 32;
- else
- tmp_event_count = pop->event_count * 2;
-
- /* We need more file descriptors */
- tmp_event_set = realloc(pop->event_set,
- tmp_event_count * sizeof(struct pollfd));
- if (tmp_event_set == NULL) {
- event_warn("realloc");
- return (-1);
- }
- pop->event_set = tmp_event_set;
-
- tmp_event_r_back = realloc(pop->event_r_back,
- tmp_event_count * sizeof(struct event *));
- if (tmp_event_r_back == NULL) {
- /* event_set overallocated; that's okay. */
- event_warn("realloc");
- return (-1);
- }
- pop->event_r_back = tmp_event_r_back;
-
- tmp_event_w_back = realloc(pop->event_w_back,
- tmp_event_count * sizeof(struct event *));
- if (tmp_event_w_back == NULL) {
- /* event_set and event_r_back overallocated; that's
- * okay. */
- event_warn("realloc");
- return (-1);
- }
- pop->event_w_back = tmp_event_w_back;
-
- pop->event_count = tmp_event_count;
- }
- if (ev->ev_fd >= pop->fd_count) {
- int *tmp_idxplus1_by_fd;
- int new_count;
- if (pop->fd_count < 32)
- new_count = 32;
- else
- new_count = pop->fd_count * 2;
- while (new_count <= ev->ev_fd)
- new_count *= 2;
- tmp_idxplus1_by_fd =
- realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
- if (tmp_idxplus1_by_fd == NULL) {
- event_warn("realloc");
- return (-1);
- }
- pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
- memset(pop->idxplus1_by_fd + pop->fd_count,
- 0, sizeof(int)*(new_count - pop->fd_count));
- pop->fd_count = new_count;
- }
-
- i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
- if (i >= 0) {
- pfd = &pop->event_set[i];
- } else {
- i = pop->nfds++;
- pfd = &pop->event_set[i];
- pfd->events = 0;
- pfd->fd = ev->ev_fd;
- pop->event_w_back[i] = pop->event_r_back[i] = NULL;
- pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
- }
-
- pfd->revents = 0;
- if (ev->ev_events & EV_WRITE) {
- pfd->events |= POLLOUT;
- pop->event_w_back[i] = ev;
- }
- if (ev->ev_events & EV_READ) {
- pfd->events |= POLLIN;
- pop->event_r_back[i] = ev;
- }
- poll_check_ok(pop);
-
- return (0);
-}
-
-/*
- * Nothing to be done here.
- */
-
-static int
-poll_del(void *arg, struct event *ev)
-{
- struct pollop *pop = arg;
- struct pollfd *pfd = NULL;
- int i;
-
- if (ev->ev_events & EV_SIGNAL)
- return (evsignal_del(ev));
-
- if (!(ev->ev_events & (EV_READ|EV_WRITE)))
- return (0);
-
- poll_check_ok(pop);
- i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
- if (i < 0)
- return (-1);
-
- /* Do we still want to read or write? */
- pfd = &pop->event_set[i];
- if (ev->ev_events & EV_READ) {
- pfd->events &= ~POLLIN;
- pop->event_r_back[i] = NULL;
- }
- if (ev->ev_events & EV_WRITE) {
- pfd->events &= ~POLLOUT;
- pop->event_w_back[i] = NULL;
- }
- poll_check_ok(pop);
- if (pfd->events)
- /* Another event cares about that fd. */
- return (0);
-
- /* Okay, so we aren't interested in that fd anymore. */
- pop->idxplus1_by_fd[ev->ev_fd] = 0;
-
- --pop->nfds;
- if (i != pop->nfds) {
- /*
- * Shift the last pollfd down into the now-unoccupied
- * position.
- */
- memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
- sizeof(struct pollfd));
- pop->event_r_back[i] = pop->event_r_back[pop->nfds];
- pop->event_w_back[i] = pop->event_w_back[pop->nfds];
- pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
- }
-
- poll_check_ok(pop);
- return (0);
-}
-
-static void
-poll_dealloc(struct event_base *base, void *arg)
-{
- struct pollop *pop = arg;
-
- evsignal_dealloc(base);
- if (pop->event_set)
- free(pop->event_set);
- if (pop->event_r_back)
- free(pop->event_r_back);
- if (pop->event_w_back)
- free(pop->event_w_back);
- if (pop->idxplus1_by_fd)
- free(pop->idxplus1_by_fd);
-
- memset(pop, 0, sizeof(struct pollop));
- free(pop);
-}
diff --git a/lib/libevent/shlib_version b/lib/libevent/shlib_version
deleted file mode 100644
index ca29af41c17..00000000000
--- a/lib/libevent/shlib_version
+++ /dev/null
@@ -1,5 +0,0 @@
-# $NetBSD: shlib_version,v 1.6 2009/07/08 21:23:53 tls Exp $
-# Remember to update distrib/sets/lists/base/shl.* when changing
-#
-major=3
-minor=1
diff --git a/lib/libevent/signal.c b/lib/libevent/signal.c
deleted file mode 100644
index a777c2e3b52..00000000000
--- a/lib/libevent/signal.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/* $NetBSD: signal.c,v 1.7 2009/07/08 21:23:53 tls Exp $ */
-/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
-
-/*
- * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Niels Provos.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "config.h"
-
-#include <sys/types.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <sys/queue.h>
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <assert.h>
-
-#include "event.h"
-#include "event-internal.h"
-#include "evsignal.h"
-#include "evutil.h"
-#include "log.h"
-
-struct event_base *evsignal_base = NULL;
-
-static void evsignal_handler(int sig);
-
-/* Callback for when the signal handler write a byte to our signaling socket */
-static void
-evsignal_cb(int fd, short what, void *arg)
-{
- static char signals[1];
- ssize_t n;
-
- n = recv(fd, signals, sizeof(signals), 0);
- if (n == -1)
- event_err(1, "%s: read", __func__);
-}
-
-#ifdef HAVE_SETFD
-#define FD_CLOSEONEXEC(x) do { \
- if (fcntl(x, F_SETFD, 1) == -1) \
- event_warn("fcntl(%d, F_SETFD)", x); \
-} while (0)
-#else
-#define FD_CLOSEONEXEC(x)
-#endif
-
-void
-evsignal_init(struct event_base *base)
-{
- int i;
-
- /*
- * Our signal handler is going to write to one end of the socket
- * pair to wake up our event loop. The event loop then scans for
- * signals that got delivered.
- */
- if (evutil_socketpair(
- AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1)
- event_err(1, "%s: socketpair", __func__);
-
- FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);
- FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);
- base->sig.sh_old = NULL;
- base->sig.sh_old_max = 0;
- base->sig.evsignal_caught = 0;
- memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
- /* initialize the queues for all events */
- for (i = 0; i < NSIG; ++i)
- TAILQ_INIT(&base->sig.evsigevents[i]);
-
- evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
-
- event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
- EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
- base->sig.ev_signal.ev_base = base;
- base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
-}
-
-/* Helper: set the signal handler for evsignal to handler in base, so that
- * we can restore the original handler when we clear the current one. */
-int
-_evsignal_set_handler(struct event_base *base,
- int evsignal, void (*handler)(int))
-{
-#ifdef HAVE_SIGACTION
- struct sigaction sa;
-#else
- ev_sighandler_t sh;
-#endif
- struct evsignal_info *sig = &base->sig;
- void *p;
-
- /*
- * resize saved signal handler array up to the highest signal number.
- * a dynamic array is used to keep footprint on the low side.
- */
- if (evsignal >= sig->sh_old_max) {
- int new_max = evsignal + 1;
- event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
- __func__, evsignal, sig->sh_old_max));
- p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
- if (p == NULL) {
- event_warn("realloc");
- return (-1);
- }
-
- memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
- 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
-
- sig->sh_old_max = new_max;
- sig->sh_old = p;
- }
-
- /* allocate space for previous handler out of dynamic array */
- sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]);
- if (sig->sh_old[evsignal] == NULL) {
- event_warn("malloc");
- return (-1);
- }
-
- /* save previous handler and setup new handler */
-#ifdef HAVE_SIGACTION
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = handler;
- sa.sa_flags |= SA_RESTART;
- sigfillset(&sa.sa_mask);
-
- if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
- event_warn("sigaction");
- free(sig->sh_old[evsignal]);
- return (-1);
- }
-#else
- if ((sh = signal(evsignal, handler)) == SIG_ERR) {
- event_warn("signal");
- free(sig->sh_old[evsignal]);
- return (-1);
- }
- *sig->sh_old[evsignal] = sh;
-#endif
-
- return (0);
-}
-
-int
-evsignal_add(struct event *ev)
-{
- int evsignal;
- struct event_base *base = ev->ev_base;
- struct evsignal_info *sig = &ev->ev_base->sig;
-
- if (ev->ev_events & (EV_READ|EV_WRITE))
- event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
- evsignal = EVENT_SIGNAL(ev);
- assert(evsignal >= 0 && evsignal < NSIG);
- if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {
- event_debug(("%s: %p: changing signal handler", __func__, ev));
- if (_evsignal_set_handler(
- base, evsignal, evsignal_handler) == -1)
- return (-1);
-
- /* catch signals if they happen quickly */
- evsignal_base = base;
-
- if (!sig->ev_signal_added) {
- if (event_add(&sig->ev_signal, NULL))
- return (-1);
- sig->ev_signal_added = 1;
- }
- }
-
- /* multiple events may listen to the same signal */
- TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);
-
- return (0);
-}
-
-int
-_evsignal_restore_handler(struct event_base *base, int evsignal)
-{
- int ret = 0;
- struct evsignal_info *sig = &base->sig;
-#ifdef HAVE_SIGACTION
- struct sigaction *sh;
-#else
- ev_sighandler_t *sh;
-#endif
-
- /* restore previous handler */
- sh = sig->sh_old[evsignal];
- sig->sh_old[evsignal] = NULL;
-#ifdef HAVE_SIGACTION
- if (sigaction(evsignal, sh, NULL) == -1) {
- event_warn("sigaction");
- ret = -1;
- }
-#else
- if (signal(evsignal, *sh) == SIG_ERR) {
- event_warn("signal");
- ret = -1;
- }
-#endif
- free(sh);
-
- return ret;
-}
-
-int
-evsignal_del(struct event *ev)
-{
- struct event_base *base = ev->ev_base;
- struct evsignal_info *sig = &base->sig;
- int evsignal = EVENT_SIGNAL(ev);
-
- assert(evsignal >= 0 && evsignal < NSIG);
-
- /* multiple events may listen to the same signal */
- TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next);
-
- if (!TAILQ_EMPTY(&sig->evsigevents[evsignal]))
- return (0);
-
- event_debug(("%s: %p: restoring signal handler", __func__, ev));
-
- return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev)));
-}
-
-static void
-evsignal_handler(int sig)
-{
- int save_errno = errno;
-
- if (evsignal_base == NULL) {
- event_warn(
- "%s: received signal %d, but have no base configured",
- __func__, sig);
- return;
- }
-
- evsignal_base->sig.evsigcaught[sig]++;
- evsignal_base->sig.evsignal_caught = 1;
-
-#ifndef HAVE_SIGACTION
- signal(sig, evsignal_handler);
-#endif
-
- /* Wake up our notification mechanism */
- send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
- errno = save_errno;
-}
-
-void
-evsignal_process(struct event_base *base)
-{
- struct evsignal_info *sig = &base->sig;
- struct event *ev, *next_ev;
- sig_atomic_t ncalls;
- int i;
-
- base->sig.evsignal_caught = 0;
- for (i = 1; i < NSIG; ++i) {
- ncalls = sig->evsigcaught[i];
- if (ncalls == 0)
- continue;
- sig->evsigcaught[i] -= ncalls;
-
- for (ev = TAILQ_FIRST(&sig->evsigevents[i]);
- ev != NULL; ev = next_ev) {
- next_ev = TAILQ_NEXT(ev, ev_signal_next);
- if (!(ev->ev_events & EV_PERSIST))
- event_del(ev);
- event_active(ev, EV_SIGNAL, ncalls);
- }
-
- }
-}
-
-void
-evsignal_dealloc(struct event_base *base)
-{
- int i = 0;
- if (base->sig.ev_signal_added) {
- event_del(&base->sig.ev_signal);
- base->sig.ev_signal_added = 0;
- }
- for (i = 0; i < NSIG; ++i) {
- if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
- _evsignal_restore_handler(base, i);
- }
-
- EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
- base->sig.ev_signal_pair[0] = -1;
- EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
- base->sig.ev_signal_pair[1] = -1;
- base->sig.sh_old_max = 0;
-
- /* per index frees are handled in evsignal_del() */
- free(base->sig.sh_old);
-}