remove old libevent sources
This commit is contained in:
parent
c75313ecdf
commit
212bd4a35c
@ -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
|
@ -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>
|
@ -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;
|
||||
}
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -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.
|
2917
lib/libevent/evdns.c
2917
lib/libevent/evdns.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
@ -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_ */
|
@ -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.
|
1001
lib/libevent/event.c
1001
lib/libevent/event.c
File diff suppressed because it is too large
Load Diff
1163
lib/libevent/event.h
1163
lib/libevent/event.h
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
@ -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 <, >, ",
|
||||
* ' and & 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_ */
|
@ -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_ */
|
@ -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);
|
||||
}
|
@ -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_ */
|
@ -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_ */
|
@ -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;
|
||||
}
|
@ -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_ */
|
@ -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 */
|
2748
lib/libevent/http.c
2748
lib/libevent/http.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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_ */
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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
@ -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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user