remove old libevent sources

This commit is contained in:
plunky 2009-11-02 10:14:28 +00:00
parent c75313ecdf
commit 212bd4a35c
37 changed files with 0 additions and 19798 deletions

View File

@ -1,37 +0,0 @@
# $NetBSD: Makefile,v 1.5 2009/07/21 01:00:45 mrg Exp $
# Generated from: NetBSD: build-makefiles,v 1.7 2009/07/21 00:23:02 mrg Exp
NOLINT= # defined
NOMAN= # defined
NONLS= # defined
NOINFO= # defined
NOSHARE= # defined
NOCHECKVER= # defined
.include <bsd.obj.mk>
# Resolve pathnames in variables.
_RESOLVE_VARS= CFLAGS CPPFLAGS DPADD LDADD LIBDPLIBS LIB_ROOT_DIR
.for var in ${_RESOLVE_VARS}
${var}:= ${${var}}
.endfor
.include <bsd.own.mk>
_CURDIR:= ${.CURDIR}
.PATH: ${NETBSDSRCDIR}/lib/libevent
.CURDIR:=${NETBSDSRCDIR}/lib/libevent
.include "${NETBSDSRCDIR}/compat/Makefile.compat"
.include "${.CURDIR}/Makefile"
# Resolve pathnames from "real" Makefile, and switch .CURDIR back.
_RESOLVE_VARS= CFLAGS CPPFLAGS DPADD LDADD ARCHDIR COMPATDIR COMPATARCHDIR LIBCDIR RPC_INCS RPC_XDIR LIBEDITDIR MODOBJDIR RUMPTOP
.for var in ${_RESOLVE_VARS}
${var}:= ${${var}}
.endfor
.CURDIR:= ${_CURDIR}
.undef _CURDIR

View File

@ -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>

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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_ */

View File

@ -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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -1,21 +0,0 @@
# $NetBSD: Makefile,v 1.4 2008/05/16 20:24:57 peter Exp $
NOMAN= # defined
CPPFLAGS+=-DHAVE_CONFIG_H -I${.CURDIR}/../../../lib/libevent
SRCS= regress.c regress.gen.c regress_dns.c regress_http.c regress_rpc.c
PROG= eventtest
DPADD+= ${LIBEVENT}
LDADD+= -levent
.PATH: ${.CURDIR}/..
regress: eventtest
@echo Testing libevent
@EVENT_SHOW_METHOD="yes" EVENT_NOPOLL="yes" ./eventtest
@echo
@EVENT_SHOW_METHOD="yes" EVENT_NOKQUEUE="yes" ./eventtest
.include <bsd.prog.mk>

File diff suppressed because it is too large Load Diff

View File

@ -1,872 +0,0 @@
/*
* Automatically generated from regress.rpc
* by event_rpcgen.py/0.1. DO NOT EDIT THIS FILE.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <event.h>
#include "regress.gen.h"
void event_err(int eval, const char *fmt, ...);
void event_warn(const char *fmt, ...);
void event_errx(int eval, const char *fmt, ...);
void event_warnx(const char *fmt, ...);
/*
* Implementation of msg
*/
static struct msg_access_ __msg_base = {
msg_from_name_assign,
msg_from_name_get,
msg_to_name_assign,
msg_to_name_get,
msg_attack_assign,
msg_attack_get,
msg_run_assign,
msg_run_get,
msg_run_add,
};
struct msg *
msg_new(void)
{
struct msg *tmp;
if ((tmp = malloc(sizeof(struct msg))) == NULL) {
event_warn("%s: malloc", __func__);
return (NULL);
}
tmp->base = &__msg_base;
tmp->from_name_data = NULL;
tmp->from_name_set = 0;
tmp->to_name_data = NULL;
tmp->to_name_set = 0;
tmp->attack_data = NULL;
tmp->attack_set = 0;
tmp->run_data = NULL;
tmp->run_length = 0;
tmp->run_num_allocated = 0;
tmp->run_set = 0;
return (tmp);
}
struct run *
msg_run_add(struct msg *msg)
{
if (++msg->run_length >= msg->run_num_allocated) {
int tobe_allocated = msg->run_num_allocated;
struct run ** new_data = NULL;
tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
new_data = (struct run **) realloc(msg->run_data,
tobe_allocated * sizeof(struct run *));
if (new_data == NULL)
goto error;
msg->run_data = new_data;
msg->run_num_allocated = tobe_allocated;
}
msg->run_data[msg->run_length - 1] = run_new();
if (msg->run_data[msg->run_length - 1] == NULL)
goto error;
msg->run_set = 1;
return (msg->run_data[msg->run_length - 1]);
error:
--msg->run_length;
return (NULL);
}
int
msg_from_name_assign(struct msg *msg,
const char * value)
{
if (msg->from_name_data != NULL)
free(msg->from_name_data);
if ((msg->from_name_data = strdup(value)) == NULL)
return (-1);
msg->from_name_set = 1;
return (0);
}
int
msg_to_name_assign(struct msg *msg,
const char * value)
{
if (msg->to_name_data != NULL)
free(msg->to_name_data);
if ((msg->to_name_data = strdup(value)) == NULL)
return (-1);
msg->to_name_set = 1;
return (0);
}
int
msg_attack_assign(struct msg *msg,
const struct kill* value)
{
struct evbuffer *tmp = NULL;
if (msg->attack_set) {
kill_clear(msg->attack_data);
msg->attack_set = 0;
} else {
msg->attack_data = kill_new();
if (msg->attack_data == NULL) {
event_warn("%s: kill_new()", __func__);
goto error;
}
}
if ((tmp = evbuffer_new()) == NULL) {
event_warn("%s: evbuffer_new()", __func__);
goto error;
}
kill_marshal(tmp, value);
if (kill_unmarshal(msg->attack_data, tmp) == -1) {
event_warnx("%s: kill_unmarshal", __func__);
goto error;
}
msg->attack_set = 1;
evbuffer_free(tmp);
return (0);
error:
if (tmp != NULL)
evbuffer_free(tmp);
if (msg->attack_data != NULL) {
kill_free(msg->attack_data);
msg->attack_data = NULL;
}
return (-1);
}
int
msg_run_assign(struct msg *msg, int off,
const struct run * value)
{
struct evbuffer *tmp = NULL;
if (!msg->run_set || off < 0 || off >= msg->run_length)
return (-1);
run_clear(msg->run_data[off]);
if ((tmp = evbuffer_new()) == NULL) {
event_warn("%s: evbuffer_new()", __func__);
goto error;
}
run_marshal(tmp, value);
if (run_unmarshal(msg->run_data[off], tmp) == -1) {
event_warnx("%s: run_unmarshal", __func__);
goto error;
}
evbuffer_free(tmp);
return (0);
error:
if (tmp != NULL)
evbuffer_free(tmp);
run_clear(msg->run_data[off]);
return (-1);
}
int
msg_from_name_get(struct msg *msg, char * *value)
{
if (msg->from_name_set != 1)
return (-1);
*value = msg->from_name_data;
return (0);
}
int
msg_to_name_get(struct msg *msg, char * *value)
{
if (msg->to_name_set != 1)
return (-1);
*value = msg->to_name_data;
return (0);
}
int
msg_attack_get(struct msg *msg, struct kill* *value)
{
if (msg->attack_set != 1) {
msg->attack_data = kill_new();
if (msg->attack_data == NULL)
return (-1);
msg->attack_set = 1;
}
*value = msg->attack_data;
return (0);
}
int
msg_run_get(struct msg *msg, int offset,
struct run * *value)
{
if (!msg->run_set || offset < 0 || offset >= msg->run_length)
return (-1);
*value = msg->run_data[offset];
return (0);
}
void
msg_clear(struct msg *tmp)
{
if (tmp->from_name_set == 1) {
free (tmp->from_name_data);
tmp->from_name_data = NULL;
tmp->from_name_set = 0;
}
if (tmp->to_name_set == 1) {
free (tmp->to_name_data);
tmp->to_name_data = NULL;
tmp->to_name_set = 0;
}
if (tmp->attack_set == 1) {
kill_free(tmp->attack_data);
tmp->attack_data = NULL;
tmp->attack_set = 0;
}
if (tmp->run_set == 1) {
int i;
for (i = 0; i < tmp->run_length; ++i) {
run_free(tmp->run_data[i]);
}
free(tmp->run_data);
tmp->run_data = NULL;
tmp->run_set = 0;
tmp->run_length = 0;
tmp->run_num_allocated = 0;
}
}
void
msg_free(struct msg *tmp)
{
if (tmp->from_name_data != NULL)
free (tmp->from_name_data);
if (tmp->to_name_data != NULL)
free (tmp->to_name_data);
if (tmp->attack_data != NULL)
kill_free(tmp->attack_data);
if (tmp->run_data != NULL) {
int i;
for (i = 0; i < tmp->run_length; ++i) {
run_free(tmp->run_data[i]);
tmp->run_data[i] = NULL;
}
free(tmp->run_data);
tmp->run_data = NULL;
tmp->run_length = 0;
tmp->run_num_allocated = 0;
}
free(tmp);
}
void
msg_marshal(struct evbuffer *evbuf, const struct msg *tmp){
evtag_marshal_string(evbuf, MSG_FROM_NAME, tmp->from_name_data);
evtag_marshal_string(evbuf, MSG_TO_NAME, tmp->to_name_data);
if (tmp->attack_set) {
evtag_marshal_kill(evbuf, MSG_ATTACK, tmp->attack_data);
}
{
int i;
for (i = 0; i < tmp->run_length; ++i) {
evtag_marshal_run(evbuf, MSG_RUN, tmp->run_data[i]);
}
}
}
int
msg_unmarshal(struct msg *tmp, struct evbuffer *evbuf)
{
uint32_t tag;
while (EVBUFFER_LENGTH(evbuf) > 0) {
if (evtag_peek(evbuf, &tag) == -1)
return (-1);
switch (tag) {
case MSG_FROM_NAME:
if (tmp->from_name_set)
return (-1);
if (evtag_unmarshal_string(evbuf, MSG_FROM_NAME, &tmp->from_name_data) == -1) {
event_warnx("%s: failed to unmarshal from_name", __func__);
return (-1);
}
tmp->from_name_set = 1;
break;
case MSG_TO_NAME:
if (tmp->to_name_set)
return (-1);
if (evtag_unmarshal_string(evbuf, MSG_TO_NAME, &tmp->to_name_data) == -1) {
event_warnx("%s: failed to unmarshal to_name", __func__);
return (-1);
}
tmp->to_name_set = 1;
break;
case MSG_ATTACK:
if (tmp->attack_set)
return (-1);
tmp->attack_data = kill_new();
if (tmp->attack_data == NULL)
return (-1);
if (evtag_unmarshal_kill(evbuf, MSG_ATTACK, tmp->attack_data) == -1) {
event_warnx("%s: failed to unmarshal attack", __func__);
return (-1);
}
tmp->attack_set = 1;
break;
case MSG_RUN:
if (msg_run_add(tmp) == NULL)
return (-1);
if (evtag_unmarshal_run(evbuf, MSG_RUN,
tmp->run_data[tmp->run_length - 1]) == -1) {
--tmp->run_length;
event_warnx("%s: failed to unmarshal run", __func__);
return (-1);
}
tmp->run_set = 1;
break;
default:
return -1;
}
}
if (msg_complete(tmp) == -1)
return (-1);
return (0);
}
int
msg_complete(struct msg *msg)
{
if (!msg->from_name_set)
return (-1);
if (!msg->to_name_set)
return (-1);
if (msg->attack_set && kill_complete(msg->attack_data) == -1)
return (-1);
{
int i;
for (i = 0; i < msg->run_length; ++i) {
if (run_complete(msg->run_data[i]) == -1)
return (-1);
}
}
return (0);
}
int
evtag_unmarshal_msg(struct evbuffer *evbuf, uint32_t need_tag, struct msg *msg)
{
uint32_t tag;
int res = -1;
struct evbuffer *tmp = evbuffer_new();
if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
goto error;
if (msg_unmarshal(msg, tmp) == -1)
goto error;
res = 0;
error:
evbuffer_free(tmp);
return (res);
}
void
evtag_marshal_msg(struct evbuffer *evbuf, uint32_t tag, const struct msg *msg)
{
struct evbuffer *_buf = evbuffer_new();
assert(_buf != NULL);
evbuffer_drain(_buf, -1);
msg_marshal(_buf, msg);
evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), EVBUFFER_LENGTH(_buf));
evbuffer_free(_buf);
}
/*
* Implementation of kill
*/
static struct kill_access_ __kill_base = {
kill_weapon_assign,
kill_weapon_get,
kill_action_assign,
kill_action_get,
kill_how_often_assign,
kill_how_often_get,
};
struct kill *
kill_new(void)
{
struct kill *tmp;
if ((tmp = malloc(sizeof(struct kill))) == NULL) {
event_warn("%s: malloc", __func__);
return (NULL);
}
tmp->base = &__kill_base;
tmp->weapon_data = NULL;
tmp->weapon_set = 0;
tmp->action_data = NULL;
tmp->action_set = 0;
tmp->how_often_data = 0;
tmp->how_often_set = 0;
return (tmp);
}
int
kill_weapon_assign(struct kill *msg,
const char * value)
{
if (msg->weapon_data != NULL)
free(msg->weapon_data);
if ((msg->weapon_data = strdup(value)) == NULL)
return (-1);
msg->weapon_set = 1;
return (0);
}
int
kill_action_assign(struct kill *msg,
const char * value)
{
if (msg->action_data != NULL)
free(msg->action_data);
if ((msg->action_data = strdup(value)) == NULL)
return (-1);
msg->action_set = 1;
return (0);
}
int
kill_how_often_assign(struct kill *msg, const uint32_t value)
{
msg->how_often_set = 1;
msg->how_often_data = value;
return (0);
}
int
kill_weapon_get(struct kill *msg, char * *value)
{
if (msg->weapon_set != 1)
return (-1);
*value = msg->weapon_data;
return (0);
}
int
kill_action_get(struct kill *msg, char * *value)
{
if (msg->action_set != 1)
return (-1);
*value = msg->action_data;
return (0);
}
int
kill_how_often_get(struct kill *msg, uint32_t *value)
{
if (msg->how_often_set != 1)
return (-1);
*value = msg->how_often_data;
return (0);
}
void
kill_clear(struct kill *tmp)
{
if (tmp->weapon_set == 1) {
free (tmp->weapon_data);
tmp->weapon_data = NULL;
tmp->weapon_set = 0;
}
if (tmp->action_set == 1) {
free (tmp->action_data);
tmp->action_data = NULL;
tmp->action_set = 0;
}
tmp->how_often_set = 0;
}
void
kill_free(struct kill *tmp)
{
if (tmp->weapon_data != NULL)
free (tmp->weapon_data);
if (tmp->action_data != NULL)
free (tmp->action_data);
free(tmp);
}
void
kill_marshal(struct evbuffer *evbuf, const struct kill *tmp){
evtag_marshal_string(evbuf, KILL_WEAPON, tmp->weapon_data);
evtag_marshal_string(evbuf, KILL_ACTION, tmp->action_data);
if (tmp->how_often_set) {
evtag_marshal_int(evbuf, KILL_HOW_OFTEN, tmp->how_often_data);
}
}
int
kill_unmarshal(struct kill *tmp, struct evbuffer *evbuf)
{
uint32_t tag;
while (EVBUFFER_LENGTH(evbuf) > 0) {
if (evtag_peek(evbuf, &tag) == -1)
return (-1);
switch (tag) {
case KILL_WEAPON:
if (tmp->weapon_set)
return (-1);
if (evtag_unmarshal_string(evbuf, KILL_WEAPON, &tmp->weapon_data) == -1) {
event_warnx("%s: failed to unmarshal weapon", __func__);
return (-1);
}
tmp->weapon_set = 1;
break;
case KILL_ACTION:
if (tmp->action_set)
return (-1);
if (evtag_unmarshal_string(evbuf, KILL_ACTION, &tmp->action_data) == -1) {
event_warnx("%s: failed to unmarshal action", __func__);
return (-1);
}
tmp->action_set = 1;
break;
case KILL_HOW_OFTEN:
if (tmp->how_often_set)
return (-1);
if (evtag_unmarshal_int(evbuf, KILL_HOW_OFTEN, &tmp->how_often_data) == -1) {
event_warnx("%s: failed to unmarshal how_often", __func__);
return (-1);
}
tmp->how_often_set = 1;
break;
default:
return -1;
}
}
if (kill_complete(tmp) == -1)
return (-1);
return (0);
}
int
kill_complete(struct kill *msg)
{
if (!msg->weapon_set)
return (-1);
if (!msg->action_set)
return (-1);
return (0);
}
int
evtag_unmarshal_kill(struct evbuffer *evbuf, uint32_t need_tag, struct kill *msg)
{
uint32_t tag;
int res = -1;
struct evbuffer *tmp = evbuffer_new();
if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
goto error;
if (kill_unmarshal(msg, tmp) == -1)
goto error;
res = 0;
error:
evbuffer_free(tmp);
return (res);
}
void
evtag_marshal_kill(struct evbuffer *evbuf, uint32_t tag, const struct kill *msg)
{
struct evbuffer *_buf = evbuffer_new();
assert(_buf != NULL);
evbuffer_drain(_buf, -1);
kill_marshal(_buf, msg);
evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), EVBUFFER_LENGTH(_buf));
evbuffer_free(_buf);
}
/*
* Implementation of run
*/
static struct run_access_ __run_base = {
run_how_assign,
run_how_get,
run_some_bytes_assign,
run_some_bytes_get,
run_fixed_bytes_assign,
run_fixed_bytes_get,
};
struct run *
run_new(void)
{
struct run *tmp;
if ((tmp = malloc(sizeof(struct run))) == NULL) {
event_warn("%s: malloc", __func__);
return (NULL);
}
tmp->base = &__run_base;
tmp->how_data = NULL;
tmp->how_set = 0;
tmp->some_bytes_data = NULL;
tmp->some_bytes_length = 0;
tmp->some_bytes_set = 0;
memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
tmp->fixed_bytes_set = 0;
return (tmp);
}
int
run_how_assign(struct run *msg,
const char * value)
{
if (msg->how_data != NULL)
free(msg->how_data);
if ((msg->how_data = strdup(value)) == NULL)
return (-1);
msg->how_set = 1;
return (0);
}
int
run_some_bytes_assign(struct run *msg, const uint8_t * value, uint32_t len)
{
if (msg->some_bytes_data != NULL)
free (msg->some_bytes_data);
msg->some_bytes_data = malloc(len);
if (msg->some_bytes_data == NULL)
return (-1);
msg->some_bytes_set = 1;
msg->some_bytes_length = len;
memcpy(msg->some_bytes_data, value, len);
return (0);
}
int
run_fixed_bytes_assign(struct run *msg, const uint8_t *value)
{
msg->fixed_bytes_set = 1;
memcpy(msg->fixed_bytes_data, value, 24);
return (0);
}
int
run_how_get(struct run *msg, char * *value)
{
if (msg->how_set != 1)
return (-1);
*value = msg->how_data;
return (0);
}
int
run_some_bytes_get(struct run *msg, uint8_t * *value, uint32_t *plen)
{
if (msg->some_bytes_set != 1)
return (-1);
*value = msg->some_bytes_data;
*plen = msg->some_bytes_length;
return (0);
}
int
run_fixed_bytes_get(struct run *msg, uint8_t **value)
{
if (msg->fixed_bytes_set != 1)
return (-1);
*value = msg->fixed_bytes_data;
return (0);
}
void
run_clear(struct run *tmp)
{
if (tmp->how_set == 1) {
free (tmp->how_data);
tmp->how_data = NULL;
tmp->how_set = 0;
}
if (tmp->some_bytes_set == 1) {
free (tmp->some_bytes_data);
tmp->some_bytes_data = NULL;
tmp->some_bytes_length = 0;
tmp->some_bytes_set = 0;
}
tmp->fixed_bytes_set = 0;
memset(tmp->fixed_bytes_data, 0, sizeof(tmp->fixed_bytes_data));
}
void
run_free(struct run *tmp)
{
if (tmp->how_data != NULL)
free (tmp->how_data);
if (tmp->some_bytes_data != NULL)
free (tmp->some_bytes_data);
free(tmp);
}
void
run_marshal(struct evbuffer *evbuf, const struct run *tmp){
evtag_marshal_string(evbuf, RUN_HOW, tmp->how_data);
if (tmp->some_bytes_set) {
evtag_marshal(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length);
}
evtag_marshal(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, sizeof(tmp->fixed_bytes_data));
}
int
run_unmarshal(struct run *tmp, struct evbuffer *evbuf)
{
uint32_t tag;
while (EVBUFFER_LENGTH(evbuf) > 0) {
if (evtag_peek(evbuf, &tag) == -1)
return (-1);
switch (tag) {
case RUN_HOW:
if (tmp->how_set)
return (-1);
if (evtag_unmarshal_string(evbuf, RUN_HOW, &tmp->how_data) == -1) {
event_warnx("%s: failed to unmarshal how", __func__);
return (-1);
}
tmp->how_set = 1;
break;
case RUN_SOME_BYTES:
if (tmp->some_bytes_set)
return (-1);
if (evtag_payload_length(evbuf, &tmp->some_bytes_length) == -1)
return (-1);
if (tmp->some_bytes_length > EVBUFFER_LENGTH(evbuf))
return (-1);
if ((tmp->some_bytes_data = malloc(tmp->some_bytes_length)) == NULL)
return (-1);
if (evtag_unmarshal_fixed(evbuf, RUN_SOME_BYTES, tmp->some_bytes_data, tmp->some_bytes_length) == -1) {
event_warnx("%s: failed to unmarshal some_bytes", __func__);
return (-1);
}
tmp->some_bytes_set = 1;
break;
case RUN_FIXED_BYTES:
if (tmp->fixed_bytes_set)
return (-1);
if (evtag_unmarshal_fixed(evbuf, RUN_FIXED_BYTES, tmp->fixed_bytes_data, sizeof(tmp->fixed_bytes_data)) == -1) {
event_warnx("%s: failed to unmarshal fixed_bytes", __func__);
return (-1);
}
tmp->fixed_bytes_set = 1;
break;
default:
return -1;
}
}
if (run_complete(tmp) == -1)
return (-1);
return (0);
}
int
run_complete(struct run *msg)
{
if (!msg->how_set)
return (-1);
if (!msg->fixed_bytes_set)
return (-1);
return (0);
}
int
evtag_unmarshal_run(struct evbuffer *evbuf, uint32_t need_tag, struct run *msg)
{
uint32_t tag;
int res = -1;
struct evbuffer *tmp = evbuffer_new();
if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
goto error;
if (run_unmarshal(msg, tmp) == -1)
goto error;
res = 0;
error:
evbuffer_free(tmp);
return (res);
}
void
evtag_marshal_run(struct evbuffer *evbuf, uint32_t tag, const struct run *msg)
{
struct evbuffer *_buf = evbuffer_new();
assert(_buf != NULL);
evbuffer_drain(_buf, -1);
run_marshal(_buf, msg);
evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), EVBUFFER_LENGTH(_buf));
evbuffer_free(_buf);
}

View File

@ -1,178 +0,0 @@
/*
* Automatically generated from regress.rpc
*/
#ifndef _REGRESS_RPC_
#define _REGRESS_RPC_
#include <event-config.h>
#ifdef _EVENT_HAVE_STDINT_H
#include <stdint.h>
#endif
#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)
#define EVTAG_ASSIGN(msg, member, args...) (*(msg)->base->member##_assign)(msg, ## args)
#define EVTAG_GET(msg, member, args...) (*(msg)->base->member##_get)(msg, ## args)
#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)
#define EVTAG_LEN(msg, member) ((msg)->member##_length)
struct msg;
struct kill;
struct run;
/* Tag definition for msg */
enum msg_ {
MSG_FROM_NAME=1,
MSG_TO_NAME=2,
MSG_ATTACK=3,
MSG_RUN=4,
MSG_MAX_TAGS
};
/* Structure declaration for msg */
struct msg_access_ {
int (*from_name_assign)(struct msg *, const char *);
int (*from_name_get)(struct msg *, char * *);
int (*to_name_assign)(struct msg *, const char *);
int (*to_name_get)(struct msg *, char * *);
int (*attack_assign)(struct msg *, const struct kill*);
int (*attack_get)(struct msg *, struct kill* *);
int (*run_assign)(struct msg *, int, const struct run *);
int (*run_get)(struct msg *, int, struct run * *);
struct run * (*run_add)(struct msg *);
};
struct msg {
struct msg_access_ *base;
char *from_name_data;
char *to_name_data;
struct kill* attack_data;
struct run **run_data;
int run_length;
int run_num_allocated;
uint8_t from_name_set;
uint8_t to_name_set;
uint8_t attack_set;
uint8_t run_set;
};
struct msg *msg_new(void);
void msg_free(struct msg *);
void msg_clear(struct msg *);
void msg_marshal(struct evbuffer *, const struct msg *);
int msg_unmarshal(struct msg *, struct evbuffer *);
int msg_complete(struct msg *);
void evtag_marshal_msg(struct evbuffer *, uint32_t,
const struct msg *);
int evtag_unmarshal_msg(struct evbuffer *, uint32_t,
struct msg *);
int msg_from_name_assign(struct msg *, const char *);
int msg_from_name_get(struct msg *, char * *);
int msg_to_name_assign(struct msg *, const char *);
int msg_to_name_get(struct msg *, char * *);
int msg_attack_assign(struct msg *, const struct kill*);
int msg_attack_get(struct msg *, struct kill* *);
int msg_run_assign(struct msg *, int, const struct run *);
int msg_run_get(struct msg *, int, struct run * *);
struct run * msg_run_add(struct msg *);
/* --- msg done --- */
/* Tag definition for kill */
enum kill_ {
KILL_WEAPON=65825,
KILL_ACTION=2,
KILL_HOW_OFTEN=3,
KILL_MAX_TAGS
};
/* Structure declaration for kill */
struct kill_access_ {
int (*weapon_assign)(struct kill *, const char *);
int (*weapon_get)(struct kill *, char * *);
int (*action_assign)(struct kill *, const char *);
int (*action_get)(struct kill *, char * *);
int (*how_often_assign)(struct kill *, const uint32_t);
int (*how_often_get)(struct kill *, uint32_t *);
};
struct kill {
struct kill_access_ *base;
char *weapon_data;
char *action_data;
uint32_t how_often_data;
uint8_t weapon_set;
uint8_t action_set;
uint8_t how_often_set;
};
struct kill *kill_new(void);
void kill_free(struct kill *);
void kill_clear(struct kill *);
void kill_marshal(struct evbuffer *, const struct kill *);
int kill_unmarshal(struct kill *, struct evbuffer *);
int kill_complete(struct kill *);
void evtag_marshal_kill(struct evbuffer *, uint32_t,
const struct kill *);
int evtag_unmarshal_kill(struct evbuffer *, uint32_t,
struct kill *);
int kill_weapon_assign(struct kill *, const char *);
int kill_weapon_get(struct kill *, char * *);
int kill_action_assign(struct kill *, const char *);
int kill_action_get(struct kill *, char * *);
int kill_how_often_assign(struct kill *, const uint32_t);
int kill_how_often_get(struct kill *, uint32_t *);
/* --- kill done --- */
/* Tag definition for run */
enum run_ {
RUN_HOW=1,
RUN_SOME_BYTES=2,
RUN_FIXED_BYTES=3,
RUN_MAX_TAGS
};
/* Structure declaration for run */
struct run_access_ {
int (*how_assign)(struct run *, const char *);
int (*how_get)(struct run *, char * *);
int (*some_bytes_assign)(struct run *, const uint8_t *, uint32_t);
int (*some_bytes_get)(struct run *, uint8_t * *, uint32_t *);
int (*fixed_bytes_assign)(struct run *, const uint8_t *);
int (*fixed_bytes_get)(struct run *, uint8_t **);
};
struct run {
struct run_access_ *base;
char *how_data;
uint8_t *some_bytes_data;
uint32_t some_bytes_length;
uint8_t fixed_bytes_data[24];
uint8_t how_set;
uint8_t some_bytes_set;
uint8_t fixed_bytes_set;
};
struct run *run_new(void);
void run_free(struct run *);
void run_clear(struct run *);
void run_marshal(struct evbuffer *, const struct run *);
int run_unmarshal(struct run *, struct evbuffer *);
int run_complete(struct run *);
void evtag_marshal_run(struct evbuffer *, uint32_t,
const struct run *);
int evtag_unmarshal_run(struct evbuffer *, uint32_t,
struct run *);
int run_how_assign(struct run *, const char *);
int run_how_get(struct run *, char * *);
int run_some_bytes_assign(struct run *, const uint8_t *, uint32_t);
int run_some_bytes_get(struct run *, uint8_t * *, uint32_t *);
int run_fixed_bytes_assign(struct run *, const uint8_t *);
int run_fixed_bytes_get(struct run *, uint8_t **);
/* --- run done --- */
#endif /* _REGRESS_RPC_ */

View File

@ -1,46 +0,0 @@
/* $NetBSD: regress.h,v 1.1 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 _REGRESS_H_
#define _REGRESS_H_
#ifdef __cplusplus
extern "C" {
#endif
void http_suite(void);
void http_basic_test(void);
void rpc_suite(void);
void dns_suite(void);
#ifdef __cplusplus
}
#endif
#endif /* _REGRESS_H_ */

View File

@ -1,360 +0,0 @@
/* $NetBSD: regress_dns.c,v 1.2 2009/07/08 21:23:53 tls Exp $ */
/*
* Copyright (c) 2003-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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "event.h"
#include "evdns.h"
#include "log.h"
static int dns_ok = 0;
static int dns_err = 0;
void dns_suite(void);
static void
dns_gethostbyname_cb(int result, char type, int count, int ttl,
void *addresses, void *arg)
{
dns_ok = dns_err = 0;
if (result == DNS_ERR_TIMEOUT) {
fprintf(stdout, "[Timed out] ");
dns_err = result;
goto out;
}
if (result != DNS_ERR_NONE) {
fprintf(stdout, "[Error code %d] ", result);
goto out;
}
fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl);
switch (type) {
case DNS_IPv6_AAAA: {
#if defined(HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
struct in6_addr *in6_addrs = addresses;
char buf[INET6_ADDRSTRLEN+1];
int i;
/* a resolution that's not valid does not help */
if (ttl < 0)
goto out;
for (i = 0; i < count; ++i) {
const char *b = inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf));
if (b)
fprintf(stderr, "%s ", b);
else
fprintf(stderr, "%s ", strerror(errno));
}
#endif
break;
}
case DNS_IPv4_A: {
struct in_addr *in_addrs = addresses;
int i;
/* a resolution that's not valid does not help */
if (ttl < 0)
goto out;
for (i = 0; i < count; ++i)
fprintf(stderr, "%s ", inet_ntoa(in_addrs[i]));
break;
}
case DNS_PTR:
/* may get at most one PTR */
if (count != 1)
goto out;
fprintf(stderr, "%s ", *(char **)addresses);
break;
default:
goto out;
}
dns_ok = type;
out:
event_loopexit(NULL);
}
static void
dns_gethostbyname(void)
{
fprintf(stdout, "Simple DNS resolve: ");
dns_ok = 0;
evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL);
event_dispatch();
if (dns_ok == DNS_IPv4_A) {
fprintf(stdout, "OK\n");
} else {
fprintf(stdout, "FAILED\n");
exit(1);
}
}
static void
dns_gethostbyname6(void)
{
fprintf(stdout, "IPv6 DNS resolve: ");
dns_ok = 0;
evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL);
event_dispatch();
if (dns_ok == DNS_IPv6_AAAA) {
fprintf(stdout, "OK\n");
} else if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) {
fprintf(stdout, "SKIPPED\n");
} else {
fprintf(stdout, "FAILED (%d)\n", dns_ok);
exit(1);
}
}
static void
dns_gethostbyaddr(void)
{
struct in_addr in;
in.s_addr = htonl(0xcc98be0c); /* 204.152.190.12 */
fprintf(stdout, "Simple reverse DNS resolve: ");
dns_ok = 0;
evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL);
event_dispatch();
if (dns_ok == DNS_PTR) {
fprintf(stdout, "OK\n");
} else {
fprintf(stdout, "FAILED\n");
exit(1);
}
}
static int n_server_responses = 0;
static void
dns_server_request_cb(struct evdns_server_request *req, void *data)
{
int i, r;
const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa";
for (i = 0; i < req->nquestions; ++i) {
struct in_addr ans;
ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
if (req->questions[i]->type == EVDNS_TYPE_A &&
req->questions[i]->dns_question_class == EVDNS_CLASS_INET &&
!strcmp(req->questions[i]->name, "zz.example.com")) {
r = evdns_server_request_add_a_reply(req, "zz.example.com",
1, &ans.s_addr, 12345);
if (r<0)
dns_ok = 0;
} else if (req->questions[i]->type == EVDNS_TYPE_AAAA &&
req->questions[i]->dns_question_class == EVDNS_CLASS_INET &&
!strcmp(req->questions[i]->name, "zz.example.com")) {
char addr6[17] = "abcdefghijklmnop";
r = evdns_server_request_add_aaaa_reply(req, "zz.example.com",
1, addr6, 123);
if (r<0)
dns_ok = 0;
} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
req->questions[i]->dns_question_class == EVDNS_CLASS_INET &&
!strcmp(req->questions[i]->name, TEST_ARPA)) {
r = evdns_server_request_add_ptr_reply(req, NULL, TEST_ARPA,
"ZZ.EXAMPLE.COM", 54321);
if (r<0)
dns_ok = 0;
} else {
fprintf(stdout, "Unexpected question %d %d \"%s\" ",
req->questions[i]->type,
req->questions[i]->dns_question_class,
req->questions[i]->name);
dns_ok = 0;
}
}
r = evdns_server_request_respond(req, 0);
if (r<0) {
fprintf(stdout, "Couldn't send reply. ");
dns_ok = 0;
}
}
static void
dns_server_gethostbyname_cb(int result, char type, int count, int ttl,
void *addresses, void *arg)
{
if (result != DNS_ERR_NONE) {
fprintf(stdout, "Unexpected result %d. ", result);
dns_ok = 0;
goto out;
}
if (count != 1) {
fprintf(stdout, "Unexpected answer count %d. ", count);
dns_ok = 0;
goto out;
}
switch (type) {
case DNS_IPv4_A: {
struct in_addr *in_addrs = addresses;
if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) {
fprintf(stdout, "Bad IPv4 response \"%s\" %d. ",
inet_ntoa(in_addrs[0]), ttl);
dns_ok = 0;
goto out;
}
break;
}
case DNS_IPv6_AAAA: {
#if defined (HAVE_STRUCT_IN6_ADDR) && defined(HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
struct in6_addr *in6_addrs = addresses;
char buf[INET6_ADDRSTRLEN+1];
if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16)
|| ttl != 123) {
const char *b = inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf));
fprintf(stdout, "Bad IPv6 response \"%s\" %d. ", b, ttl);
dns_ok = 0;
goto out;
}
#endif
break;
}
case DNS_PTR: {
char **addrs = addresses;
if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") || ttl != 54321) {
fprintf(stdout, "Bad PTR response \"%s\" %d. ",
addrs[0], ttl);
dns_ok = 0;
goto out;
}
break;
}
default:
fprintf(stdout, "Bad response type %d. ", type);
dns_ok = 0;
}
out:
if (++n_server_responses == 3) {
event_loopexit(NULL);
}
}
static void
dns_server(void)
{
int sock;
struct sockaddr_in my_addr;
struct evdns_server_port *port;
struct in_addr resolve_addr;
dns_ok = 1;
fprintf(stdout, "DNS server support: ");
/* Add ourself as the only nameserver, and make sure we really are
* the only nameserver. */
evdns_nameserver_ip_add("127.0.0.1:35353");
if (evdns_count_nameservers() != 1) {
fprintf(stdout, "Couldn't set up.\n");
exit(1);
}
/* Now configure a nameserver port. */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
perror("socket");
exit(1);
}
fcntl(sock, F_SETFL, O_NONBLOCK);
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(35353);
my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
perror("bind");
exit (1);
}
port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL);
/* Send two queries. */
evdns_resolve_ipv4("zz.example.com", DNS_QUERY_NO_SEARCH,
dns_server_gethostbyname_cb, NULL);
evdns_resolve_ipv6("zz.example.com", DNS_QUERY_NO_SEARCH,
dns_server_gethostbyname_cb, NULL);
resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
evdns_resolve_reverse(&resolve_addr, 0,
dns_server_gethostbyname_cb, NULL);
event_dispatch();
if (dns_ok) {
fprintf(stdout, "OK\n");
} else {
fprintf(stdout, "FAILED\n");
exit(1);
}
evdns_close_server_port(port);
evdns_shutdown(0); /* remove ourself as nameserver. */
close(sock);
}
void
dns_suite(void)
{
dns_server(); /* Do this before we call evdns_init. */
evdns_init();
dns_gethostbyname();
dns_gethostbyname6();
dns_gethostbyaddr();
evdns_shutdown(0);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,625 +0,0 @@
/* $NetBSD: regress_rpc.c,v 1.2 2009/07/08 21:23:54 tls Exp $ */
/*
* Copyright (c) 2003-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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "event.h"
#include "evhttp.h"
#include "log.h"
#include "evrpc.h"
#include "regress.gen.h"
void rpc_suite(void);
extern int test_ok;
static struct evhttp *
http_setup(short *pport)
{
int i;
struct evhttp *myhttp;
short port = -1;
/* Try a few different ports */
for (i = 0; i < 50; ++i) {
myhttp = evhttp_start("127.0.0.1", 8080 + i);
if (myhttp != NULL) {
port = 8080 + i;
break;
}
}
if (port == -1)
event_errx(1, "Could not start web server");
*pport = port;
return (myhttp);
}
EVRPC_HEADER(Message, msg, kill);
EVRPC_HEADER(NeverReply, msg, kill);
EVRPC_GENERATE(Message, msg, kill);
EVRPC_GENERATE(NeverReply, msg, kill);
static int need_input_hook = 0;
static int need_output_hook = 0;
static void
MessageCb(EVRPC_STRUCT(Message)* rpc, void *arg)
{
struct kill* kill_reply = rpc->reply;
if (need_input_hook) {
struct evhttp_request* req = EVRPC_REQUEST_HTTP(rpc);
const char *header = evhttp_find_header(
req->input_headers, "X-Hook");
assert(strcmp(header, "input") == 0);
}
/* we just want to fill in some non-sense */
EVTAG_ASSIGN(kill_reply, weapon, "dagger");
EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
/* no reply to the RPC */
EVRPC_REQUEST_DONE(rpc);
}
static EVRPC_STRUCT(NeverReply) *saved_rpc;
static void
NeverReplyCb(EVRPC_STRUCT(NeverReply)* rpc, void *arg)
{
test_ok += 1;
saved_rpc = rpc;
}
static void
rpc_setup(struct evhttp **phttp, short *pport, struct evrpc_base **pbase)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
http = http_setup(&port);
base = evrpc_init(http);
EVRPC_REGISTER(base, Message, msg, kill, MessageCb, NULL);
EVRPC_REGISTER(base, NeverReply, msg, kill, NeverReplyCb, NULL);
*phttp = http;
*pport = port;
*pbase = base;
need_input_hook = 0;
need_output_hook = 0;
}
static void
rpc_teardown(struct evrpc_base *base)
{
assert(EVRPC_UNREGISTER(base, Message) == 0);
assert(EVRPC_UNREGISTER(base, NeverReply) == 0);
evrpc_free(base);
}
static void
rpc_postrequest_failure(struct evhttp_request *req, void *arg)
{
if (req->response_code != HTTP_SERVUNAVAIL) {
fprintf(stderr, "FAILED (response code)\n");
exit(1);
}
test_ok = 1;
event_loopexit(NULL);
}
/*
* Test a malformed payload submitted as an RPC
*/
static void
rpc_basic_test(void)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
fprintf(stdout, "Testing Basic RPC Support: ");
rpc_setup(&http, &port, &base);
evcon = evhttp_connection_new("127.0.0.1", port);
if (evcon == NULL) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/*
* At this point, we want to schedule an HTTP POST request
* server using our make request method.
*/
req = evhttp_request_new(rpc_postrequest_failure, NULL);
if (req == NULL) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/* Add the information that we care about */
evhttp_add_header(req->output_headers, "Host", "somehost");
evbuffer_add_printf(req->output_buffer, "Some Nonsense");
if (evhttp_make_request(evcon, req,
EVHTTP_REQ_POST,
"/.rpc.Message") == -1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
test_ok = 0;
event_dispatch();
evhttp_connection_free(evcon);
rpc_teardown(base);
if (test_ok != 1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
fprintf(stdout, "OK\n");
evhttp_free(http);
}
static void
rpc_postrequest_done(struct evhttp_request *req, void *arg)
{
struct kill* kill_reply = NULL;
if (req->response_code != HTTP_OK) {
fprintf(stderr, "FAILED (response code)\n");
exit(1);
}
kill_reply = kill_new();
if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
fprintf(stderr, "FAILED (unmarshal)\n");
exit(1);
}
kill_free(kill_reply);
test_ok = 1;
event_loopexit(NULL);
}
static void
rpc_basic_message(void)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
struct msg *msg;
fprintf(stdout, "Testing Good RPC Post: ");
rpc_setup(&http, &port, &base);
evcon = evhttp_connection_new("127.0.0.1", port);
if (evcon == NULL) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/*
* At this point, we want to schedule an HTTP POST request
* server using our make request method.
*/
req = evhttp_request_new(rpc_postrequest_done, NULL);
if (req == NULL) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/* Add the information that we care about */
evhttp_add_header(req->output_headers, "Host", "somehost");
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
msg_marshal(req->output_buffer, msg);
msg_free(msg);
if (evhttp_make_request(evcon, req,
EVHTTP_REQ_POST,
"/.rpc.Message") == -1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
test_ok = 0;
event_dispatch();
evhttp_connection_free(evcon);
rpc_teardown(base);
if (test_ok != 1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
fprintf(stdout, "OK\n");
evhttp_free(http);
}
static struct evrpc_pool *
rpc_pool_with_connection(short port)
{
struct evhttp_connection *evcon;
struct evrpc_pool *pool;
pool = evrpc_pool_new(NULL);
assert(pool != NULL);
evcon = evhttp_connection_new("127.0.0.1", port);
assert(evcon != NULL);
evrpc_pool_add_connection(pool, evcon);
return (pool);
}
static void
GotKillCb(struct evrpc_status *status,
struct msg *msg, struct kill *kill, void *arg)
{
char *weapon;
char *action;
if (need_output_hook) {
struct evhttp_request *req = status->http_req;
const char *header = evhttp_find_header(
req->input_headers, "X-Pool-Hook");
assert(strcmp(header, "ran") == 0);
}
if (status->error != EVRPC_STATUS_ERR_NONE)
goto done;
if (EVTAG_GET(kill, weapon, &weapon) == -1) {
fprintf(stderr, "get weapon\n");
goto done;
}
if (EVTAG_GET(kill, action, &action) == -1) {
fprintf(stderr, "get action\n");
goto done;
}
if (strcmp(weapon, "dagger"))
goto done;
if (strcmp(action, "wave around like an idiot"))
goto done;
test_ok += 1;
done:
event_loopexit(NULL);
}
static void
GotKillCbTwo(struct evrpc_status *status,
struct msg *msg, struct kill *kill, void *arg)
{
char *weapon;
char *action;
if (status->error != EVRPC_STATUS_ERR_NONE)
goto done;
if (EVTAG_GET(kill, weapon, &weapon) == -1) {
fprintf(stderr, "get weapon\n");
goto done;
}
if (EVTAG_GET(kill, action, &action) == -1) {
fprintf(stderr, "get action\n");
goto done;
}
if (strcmp(weapon, "dagger"))
goto done;
if (strcmp(action, "wave around like an idiot"))
goto done;
test_ok += 1;
done:
if (test_ok == 2)
event_loopexit(NULL);
}
static int
rpc_hook_add_header(struct evhttp_request *req,
struct evbuffer *evbuf, void *arg)
{
const char *hook_type = arg;
if (strcmp("input", hook_type) == 0)
evhttp_add_header(req->input_headers, "X-Hook", hook_type);
else
evhttp_add_header(req->output_headers, "X-Hook", hook_type);
return (0);
}
static int
rpc_hook_remove_header(struct evhttp_request *req,
struct evbuffer *evbuf, void *arg)
{
const char *header = evhttp_find_header(req->input_headers, "X-Hook");
assert(header != NULL);
assert(strcmp(header, arg) == 0);
evhttp_remove_header(req->input_headers, "X-Hook");
evhttp_add_header(req->input_headers, "X-Pool-Hook", "ran");
return (0);
}
static void
rpc_basic_client(void)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg;
struct kill *kill;
fprintf(stdout, "Testing RPC Client: ");
rpc_setup(&http, &port, &base);
need_input_hook = 1;
need_output_hook = 1;
assert(evrpc_add_hook(base, EVRPC_INPUT, rpc_hook_add_header, (void*)"input")
!= NULL);
assert(evrpc_add_hook(base, EVRPC_OUTPUT, rpc_hook_add_header, (void*)"output")
!= NULL);
pool = rpc_pool_with_connection(port);
assert(evrpc_add_hook(pool, EVRPC_INPUT, rpc_hook_remove_header, (void*)"output"));
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill = kill_new();
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
test_ok = 0;
event_dispatch();
if (test_ok != 1) {
fprintf(stdout, "FAILED (1)\n");
exit(1);
}
/* we do it twice to make sure that reuse works correctly */
kill_clear(kill);
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
event_dispatch();
rpc_teardown(base);
if (test_ok != 2) {
fprintf(stdout, "FAILED (2)\n");
exit(1);
}
fprintf(stdout, "OK\n");
msg_free(msg);
kill_free(kill);
evrpc_pool_free(pool);
evhttp_free(http);
}
/*
* We are testing that the second requests gets send over the same
* connection after the first RPCs completes.
*/
static void
rpc_basic_queued_client(void)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg;
struct kill *kill_one, *kill_two;
fprintf(stdout, "Testing RPC (Queued) Client: ");
rpc_setup(&http, &port, &base);
pool = rpc_pool_with_connection(port);
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill_one = kill_new();
kill_two = kill_new();
EVRPC_MAKE_REQUEST(Message, pool, msg, kill_one, GotKillCbTwo, NULL);
EVRPC_MAKE_REQUEST(Message, pool, msg, kill_two, GotKillCb, NULL);
test_ok = 0;
event_dispatch();
rpc_teardown(base);
if (test_ok != 2) {
fprintf(stdout, "FAILED (1)\n");
exit(1);
}
fprintf(stdout, "OK\n");
msg_free(msg);
kill_free(kill_one);
kill_free(kill_two);
evrpc_pool_free(pool);
evhttp_free(http);
}
static void
GotErrorCb(struct evrpc_status *status,
struct msg *msg, struct kill *kill, void *arg)
{
if (status->error != EVRPC_STATUS_ERR_TIMEOUT)
goto done;
/* should never be complete but just to check */
if (kill_complete(kill) == 0)
goto done;
test_ok += 1;
done:
event_loopexit(NULL);
}
static void
rpc_client_timeout(void)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
struct evrpc_pool *pool = NULL;
struct msg *msg;
struct kill *kill;
fprintf(stdout, "Testing RPC Client Timeout: ");
rpc_setup(&http, &port, &base);
pool = rpc_pool_with_connection(port);
/* set the timeout to 5 seconds */
evrpc_pool_set_timeout(pool, 5);
/* set up the basic message */
msg = msg_new();
EVTAG_ASSIGN(msg, from_name, "niels");
EVTAG_ASSIGN(msg, to_name, "tester");
kill = kill_new();
EVRPC_MAKE_REQUEST(NeverReply, pool, msg, kill, GotErrorCb, NULL);
test_ok = 0;
event_dispatch();
/* free the saved RPC structure up */
EVRPC_REQUEST_DONE(saved_rpc);
rpc_teardown(base);
if (test_ok != 2) {
fprintf(stdout, "FAILED (1)\n");
exit(1);
}
fprintf(stdout, "OK\n");
msg_free(msg);
kill_free(kill);
evrpc_pool_free(pool);
evhttp_free(http);
}
void
rpc_suite(void)
{
rpc_basic_test();
rpc_basic_message();
rpc_basic_client();
rpc_basic_queued_client();
rpc_client_timeout();
}