diff options
author | Vladislav Vaintroub <wlad@montyprogram.com> | 2012-02-27 19:53:49 +0100 |
---|---|---|
committer | Vladislav Vaintroub <wlad@montyprogram.com> | 2012-02-27 19:53:49 +0100 |
commit | 0d168ce514ea506a292c12d8624bfbc67fb3530f (patch) | |
tree | 4977b543850dd1c38f92e7e964071821f815852b /extra | |
parent | 62dcaf8c2911572d730ba5e617a7c3cbbf86b22a (diff) | |
download | mariadb-git-0d168ce514ea506a292c12d8624bfbc67fb3530f.tar.gz |
Remove libevent from sources - not needed now
Diffstat (limited to 'extra')
40 files changed, 0 insertions, 18726 deletions
diff --git a/extra/libevent/CMakeLists.txt b/extra/libevent/CMakeLists.txt deleted file mode 100644 index 6be15641d3e..00000000000 --- a/extra/libevent/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -INCLUDE_DIRECTORIES( - ${CMAKE_SOURCE_DIR}/extra/libevent - ${CMAKE_SOURCE_DIR}/extra/libevent/compat - ${CMAKE_SOURCE_DIR}/extra/libevent/WIN32-Code - ${CMAKE_BINARY_DIR}/extra/libevent - ${CMAKE_SOURCE_DIR}/include -) - -IF(MSVC) - ADD_DEFINITIONS("-DWIN32 -DHAVE_CONFIG_H") -ENDIF(MSVC) - -SET(LIBEVENT_SOURCES - buffer.c - evbuffer.c - event.c - evutil.c - log.c - signal.c - strlcpy.c - WIN32-Code/win32.c - WIN32-Code/config.h - WIN32-Code/misc.c - WIN32-Code/misc.h - event-internal.h - event.h - evsignal.h - evutil.h - log.h - min_heap.h - strlcpy-internal.h - ) -IF(WIN32) - # Workaround source distribution bug, remove preconfigured event-config - IF(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) - FILE(REMOVE ${CMAKE_SOURCE_DIR}/extra/libevent/event-config.h) - ENDIF() - CONFIGURE_FILE(WIN32-Code/config.h ${CMAKE_BINARY_DIR}/extra/libevent/event-config.h COPYONLY) -ENDIF() - -IF(NOT SOURCE_SUBLIBS) - ADD_LIBRARY(libevent ${LIBEVENT_SOURCES}) -ENDIF(NOT SOURCE_SUBLIBS) diff --git a/extra/libevent/README b/extra/libevent/README deleted file mode 100644 index b0650392ed4..00000000000 --- a/extra/libevent/README +++ /dev/null @@ -1,57 +0,0 @@ -To build libevent, type - -$ ./configure && make - - (If you got libevent from the subversion repository, you will - first need to run the included "autogen.sh" script in order to - generate the configure script.) - -Install as root via - -# make install - -You can run the regression tests by - -$ make verify - -Before, reporting any problems, please run the regression tests. - -To enable the low-level tracing build the library as: - -CFLAGS=-DUSE_DEBUG ./configure [...] - -Acknowledgements: ------------------ - -The following people have helped with suggestions, ideas, code or -fixing bugs: - - Alejo - Weston Andros Adamson - William Ahern - Stas Bekman - Andrew Danforth - Mike Davis - Shie Erlich - Alexander von Gernler - Artur Grabowski - Aaron Hopkins - Claudio Jeker - Scott Lamb - Adam Langley - Philip Lewis - David Libenzi - Nick Mathewson - Andrey Matveev - Richard Nyberg - Jon Oberheide - Phil Oleson - Dave Pacheco - Tassilo von Parseval - Pierre Phaneuf - Jon Poland - Bert JW Regeer - Dug Song - Taral - -If I have forgotten your name, please contact me. diff --git a/extra/libevent/WIN32-Code/config.h b/extra/libevent/WIN32-Code/config.h deleted file mode 100644 index 99365edd96a..00000000000 --- a/extra/libevent/WIN32-Code/config.h +++ /dev/null @@ -1,247 +0,0 @@ -/* config.h. Generated by configure. */ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Define if clock_gettime is available in libc */ -/* #undef DNS_USE_CPU_CLOCK_FOR_ID */ - -/* Define if no secure id variant is available */ -#define DNS_USE_FTIME_FOR_ID 1 - -/* Define if no secure id variant is available */ -/* #define DNS_USE_GETTIMEOFDAY_FOR_ID 1 */ - -/* Define to 1 if you have the `clock_gettime' function. */ -/* #undef HAVE_CLOCK_GETTIME */ - -/* Define if /dev/poll is available */ -/* #undef HAVE_DEVPOLL */ - -/* Define to 1 if you have the <dlfcn.h> header file. */ -/* #undef HAVE_DLFCN_H */ - -/* 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. */ -/* #undef HAVE_FCNTL */ - -/* 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. */ -/* #undef HAVE_GETADDRINFO */ - -/* Define to 1 if you have the `getnameinfo' function. */ -/* #undef HAVE_GETNAMEINFO */ - -/* Define to 1 if you have the `gettimeofday' function. */ -/* #define HAVE_GETTIMEOFDAY 1 */ - -/* Define to 1 if you have the `inet_ntop' function. */ -/* #undef HAVE_INET_NTOP */ - -/* Define to 1 if you have the <inttypes.h> header file. */ -/* #undef HAVE_INTTYPES_H 1 */ - -/* Define to 1 if you have the `kqueue' function. */ -/* #undef HAVE_KQUEUE */ - -/* Define to 1 if you have the `nsl' library (-lnsl). */ -/* #undef HAVE_LIBNSL */ - -/* Define to 1 if you have the `resolv' library (-lresolv). */ -/* #undef HAVE_LIBRESOLV */ - -/* Define to 1 if you have the `rt' library (-lrt). */ -/* #undef HAVE_LIBRT */ - -/* 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. */ -/* #undef HAVE_POLL */ - -/* Define to 1 if you have the <poll.h> header file. */ -/* #undef HAVE_POLL_H */ - -/* 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> */ -/* #undef HAVE_SETFD */ - -/* Define to 1 if you have the `sigaction' function. */ -/* #undef HAVE_SIGACTION */ - -/* 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. */ -/* #undef HAVE_STRLCPY */ - -/* Define to 1 if you have the `strsep' function. */ -/* #undef HAVE_STRSEP */ - -/* Define to 1 if you have the `strtok_r' function. */ -/* #undef HAVE_STRTOK_R */ - -/* 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. */ -/* #undef HAVE_SYS_EVENT_H */ - -/* Define to 1 if you have the <sys/ioctl.h> header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define to 1 if you have the <sys/queue.h> header file. */ -/* #undef HAVE_SYS_QUEUE_H */ - -/* Define to 1 if you have the <sys/select.h> header file. */ -/* #undef HAVE_SYS_SELECT_H */ - -/* Define to 1 if you have the <sys/socket.h> header file. */ -/* #undef HAVE_SYS_SOCKET_H */ - -/* 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> */ -/* #undef HAVE_TAILQFOREACH */ - -/* Define if timeradd is defined in <sys/time.h> */ -/* #undef HAVE_TIMERADD */ - -/* 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 you have the <unistd.h> header file. */ -/* #define HAVE_UNISTD_H 1 */ - -/* Define to 1 if you have the `vasprintf' function. */ -/* #undef HAVE_VASPRINTF */ - -/* Define if kqueue works correctly with pipes */ -/* #undef HAVE_WORKING_KQUEUE */ - -/* Name of package */ -#ifndef PACKAGE -#define PACKAGE "libevent" -#endif - -/* 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 "" - -/* 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.3.99-trunk" - -#ifndef __func__ -/* Define to appropriate substitue if compiler doesnt have __func__ */ -#if defined(_MSC_VER) && _MSC_VER < 1300 -#define __func__ "??" -#else -#define __func__ __FUNCTION__ -#endif -#endif - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#define inline __inline -#endif - -/* Define to `int' if <sys/types.h> does not define. */ -/* #undef pid_t */ - -/* Define to `unsigned' if <sys/types.h> does not define. */ -/* #undef size_t */ - -/* Define to unsigned int if you dont have it */ -#define socklen_t unsigned int - -/* Define to `unsigned short' if <sys/types.h> does not define. */ -#define uint16_t unsigned short - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -#define uint32_t unsigned int - -/* Define to `unsigned long long' if <sys/types.h> does not define. */ -#define uint64_t __uint64_t - -/* Define to `unsigned char' if <sys/types.h> does not define. */ -#define uint8_t unsigned char diff --git a/extra/libevent/WIN32-Code/misc.c b/extra/libevent/WIN32-Code/misc.c deleted file mode 100644 index 271c9bb399e..00000000000 --- a/extra/libevent/WIN32-Code/misc.c +++ /dev/null @@ -1,38 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <windows.h> -#include <sys/timeb.h> -#include <time.h> - -#ifdef __GNUC__ -/*our prototypes for timeval and timezone are in here, just in case the above - headers don't have them*/ -#include "misc.h" -#endif - -/**************************************************************************** - * - * Function: gettimeofday(struct timeval *, struct timezone *) - * - * Purpose: Get current time of day. - * - * Arguments: tv => Place to store the curent time of day. - * tz => Ignored. - * - * Returns: 0 => Success. - * - ****************************************************************************/ - -#ifndef HAVE_GETTIMEOFDAY -int gettimeofday(struct timeval *tv, struct timezone *tz) { - struct _timeb tb; - - if(tv == NULL) - return -1; - - _ftime(&tb); - tv->tv_sec = (long) tb.time; - tv->tv_usec = ((int) tb.millitm) * 1000; - return 0; -} -#endif diff --git a/extra/libevent/WIN32-Code/misc.h b/extra/libevent/WIN32-Code/misc.h deleted file mode 100644 index aced574687c..00000000000 --- a/extra/libevent/WIN32-Code/misc.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MISC_H -#define MISC_H - -struct timezone; -struct timeval; - -#ifndef HAVE_GETTIMEOFDAY -int gettimeofday(struct timeval *,struct timezone *); -#endif - -#endif diff --git a/extra/libevent/WIN32-Code/tree.h b/extra/libevent/WIN32-Code/tree.h deleted file mode 100644 index 79e8d91f0eb..00000000000 --- a/extra/libevent/WIN32-Code/tree.h +++ /dev/null @@ -1,1354 +0,0 @@ -/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ -/* - * Copyright 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. - * - * 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 _SYS_TREE_H_ -#define _SYS_TREE_H_ - -/* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. - * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). - */ - -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root))) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - -/* Macros that define a red-back tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (0) - -#ifndef RB_AUGMENT -#define RB_AUGMENT(x) -#endif - -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -/* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ -void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -struct type *name##_RB_REMOVE(struct name *, struct type *); \ -struct type *name##_RB_INSERT(struct name *, struct type *); \ -struct type *name##_RB_FIND(struct name *, struct type *); \ -struct type *name##_RB_NEXT(struct type *); \ -struct type *name##_RB_MINMAX(struct name *, int); \ - \ - -/* Main rb operation. - * Moves node close to the key of elm to top - */ -#define RB_GENERATE(name, type, field, cmp) \ -void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)))\ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)))\ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field))) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field))); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - \ -/* Inserts a node into the RB tree */ \ -struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} \ - \ -/* Finds the node with the same key as elm */ \ -struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} \ - \ -struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#endif /* _SYS_TREE_H_ */ -/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ -/* - * Copyright 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. - * - * 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 _SYS_TREE_H_ -#define _SYS_TREE_H_ - -/* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. - * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). - */ - -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root))) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - -/* Macros that define a red-back tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (0) - -#ifndef RB_AUGMENT -#define RB_AUGMENT(x) -#endif - -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -/* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ -void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -struct type *name##_RB_REMOVE(struct name *, struct type *); \ -struct type *name##_RB_INSERT(struct name *, struct type *); \ -struct type *name##_RB_FIND(struct name *, struct type *); \ -struct type *name##_RB_NEXT(struct type *); \ -struct type *name##_RB_MINMAX(struct name *, int); \ - \ - -/* Main rb operation. - * Moves node close to the key of elm to top - */ -#define RB_GENERATE(name, type, field, cmp) \ -void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)))\ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)))\ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field))) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field))); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - \ -/* Inserts a node into the RB tree */ \ -struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} \ - \ -/* Finds the node with the same key as elm */ \ -struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} \ - \ -struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#endif /* _SYS_TREE_H_ */ diff --git a/extra/libevent/WIN32-Code/win32.c b/extra/libevent/WIN32-Code/win32.c deleted file mode 100644 index 0d7dcfb276f..00000000000 --- a/extra/libevent/WIN32-Code/win32.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> - * Copyright 2003 Michael A. Davis <mike@datanerds.net> - * 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 _MSC_VER -#include "./config.h" -#else -/* Avoid the windows/msvc thing. */ -#include "../config.h" -#endif - -#include <winsock2.h> -#include <windows.h> -#include <sys/types.h> -#include <sys/queue.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#define RB_AUGMENT(x) (void)(x) -#include "./tree.h" -#include "log.h" -#include "event.h" -#include "event-internal.h" - -#define XFREE(ptr) do { if (ptr) free(ptr); } while(0) - -extern struct event_list timequeue; -extern struct event_list addqueue; -#if 0 -extern struct event_list signalqueue; -#endif - -struct win_fd_set { - u_int fd_count; - SOCKET fd_array[1]; -}; - -int evsigcaught[NSIG]; -volatile sig_atomic_t signal_caught = 0; -/* MSDN says this is required to handle SIGFPE */ -volatile double SIGFPE_REQ = 0.0f; - -#if 0 -static void signal_handler(int sig); - -void signal_process(void); -int signal_recalc(void); -#endif - -struct event_entry { - RB_ENTRY(event_entry) node; - SOCKET sock; - int read_pos; - int write_pos; - struct event *read_event; - struct event *write_event; -}; - -static int -compare(struct event_entry *a, struct event_entry *b) -{ - if (a->sock < b->sock) - return -1; - else if (a->sock > b->sock) - return 1; - else - return 0; -} - -struct win32op { - int fd_setsz; - struct win_fd_set *readset_in; - struct win_fd_set *writeset_in; - struct win_fd_set *readset_out; - struct win_fd_set *writeset_out; - struct win_fd_set *exset_out; - RB_HEAD(event_map, event_entry) event_root; -}; - -RB_PROTOTYPE(event_map, event_entry, node, compare); -RB_GENERATE(event_map, event_entry, node, compare); - -void *win32_init (struct event_base *); -int win32_insert (void *, struct event *); -int win32_del (void *, struct event *); -int win32_dispatch (struct event_base *base, void *, struct timeval *); -void win32_dealloc (struct event_base *, void *); - -struct eventop win32ops = { - "win32", - win32_init, - win32_insert, - win32_del, - win32_dispatch, - win32_dealloc, - 0 -}; - -#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET))) - -static int -realloc_fd_sets(struct win32op *op, size_t new_size) -{ - size_t size; - - assert(new_size >= op->readset_in->fd_count && - new_size >= op->writeset_in->fd_count); - assert(new_size >= 1); - - size = FD_SET_ALLOC_SIZE(new_size); - if (!(op->readset_in = realloc(op->readset_in, size))) - return (-1); - if (!(op->writeset_in = realloc(op->writeset_in, size))) - return (-1); - if (!(op->readset_out = realloc(op->readset_out, size))) - return (-1); - if (!(op->exset_out = realloc(op->exset_out, size))) - return (-1); - if (!(op->writeset_out = realloc(op->writeset_out, size))) - return (-1); - op->fd_setsz = (int)new_size; - return (0); -} - -static int -timeval_to_ms(struct timeval *tv) -{ - return ((tv->tv_sec * 1000) + (tv->tv_usec / 1000)); -} - -static struct event_entry* -get_event_entry(struct win32op *op, SOCKET s, int create) -{ - struct event_entry key, *val; - key.sock = s; - val = RB_FIND(event_map, &op->event_root, &key); - if (val || !create) - return val; - if (!(val = calloc(1, sizeof(struct event_entry)))) { - event_warn("%s: calloc", __func__); - return NULL; - } - val->sock = s; - val->read_pos = val->write_pos = -1; - RB_INSERT(event_map, &op->event_root, val); - return val; -} - -static int -do_fd_set(struct win32op *op, struct event_entry *ent, int read) -{ - SOCKET s = ent->sock; - struct win_fd_set *set = read ? op->readset_in : op->writeset_in; - if (read) { - if (ent->read_pos >= 0) - return (0); - } else { - if (ent->write_pos >= 0) - return (0); - } - if (set->fd_count == op->fd_setsz) { - if (realloc_fd_sets(op, op->fd_setsz*2)) - return (-1); - /* set pointer will have changed and needs reiniting! */ - set = read ? op->readset_in : op->writeset_in; - } - set->fd_array[set->fd_count] = s; - if (read) - ent->read_pos = set->fd_count; - else - ent->write_pos = set->fd_count; - return (set->fd_count++); -} - -static int -do_fd_clear(struct win32op *op, struct event_entry *ent, int read) -{ - int i; - struct win_fd_set *set = read ? op->readset_in : op->writeset_in; - if (read) { - i = ent->read_pos; - ent->read_pos = -1; - } else { - i = ent->write_pos; - ent->write_pos = -1; - } - if (i < 0) - return (0); - if (--set->fd_count != i) { - struct event_entry *ent2; - SOCKET s2; - s2 = set->fd_array[i] = set->fd_array[set->fd_count]; - ent2 = get_event_entry(op, s2, 0); - if (!ent) /* This indicates a bug. */ - return (0); - if (read) - ent2->read_pos = i; - else - ent2->write_pos = i; - } - return (0); -} - -#define NEVENT 64 -void * -win32_init(struct event_base *_base) -{ - struct win32op *winop; - size_t size; - if (!(winop = calloc(1, sizeof(struct win32op)))) - return NULL; - winop->fd_setsz = NEVENT; - size = FD_SET_ALLOC_SIZE(NEVENT); - if (!(winop->readset_in = malloc(size))) - goto err; - if (!(winop->writeset_in = malloc(size))) - goto err; - if (!(winop->readset_out = malloc(size))) - goto err; - if (!(winop->writeset_out = malloc(size))) - goto err; - if (!(winop->exset_out = malloc(size))) - goto err; - RB_INIT(&winop->event_root); - winop->readset_in->fd_count = winop->writeset_in->fd_count = 0; - winop->readset_out->fd_count = winop->writeset_out->fd_count - = winop->exset_out->fd_count = 0; - - evsignal_init(_base); - - return (winop); - err: - XFREE(winop->readset_in); - XFREE(winop->writeset_in); - XFREE(winop->readset_out); - XFREE(winop->writeset_out); - XFREE(winop->exset_out); - XFREE(winop); - return (NULL); -} - -int -win32_insert(void *op, struct event *ev) -{ - struct win32op *win32op = op; - struct event_entry *ent; - - if (ev->ev_events & EV_SIGNAL) { - return (evsignal_add(ev)); - } - if (!(ev->ev_events & (EV_READ|EV_WRITE))) - return (0); - ent = get_event_entry(win32op, ev->ev_fd, 1); - if (!ent) - return (-1); /* out of memory */ - - event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd)); - if (ev->ev_events & EV_READ) { - if (do_fd_set(win32op, ent, 1)<0) - return (-1); - ent->read_event = ev; - } - if (ev->ev_events & EV_WRITE) { - if (do_fd_set(win32op, ent, 0)<0) - return (-1); - ent->write_event = ev; - } - return (0); -} - -int -win32_del(void *op, struct event *ev) -{ - struct win32op *win32op = op; - struct event_entry *ent; - - if (ev->ev_events & EV_SIGNAL) - return (evsignal_del(ev)); - - if (!(ent = get_event_entry(win32op, ev->ev_fd, 0))) - return (-1); - event_debug(("%s: Removing event for %d", __func__, ev->ev_fd)); - if (ev == ent->read_event) { - do_fd_clear(win32op, ent, 1); - ent->read_event = NULL; - } - if (ev == ent->write_event) { - do_fd_clear(win32op, ent, 0); - ent->write_event = NULL; - } - if (!ent->read_event && !ent->write_event) { - RB_REMOVE(event_map, &win32op->event_root, ent); - free(ent); - } - - return 0; -} - -static void -fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in) -{ - out->fd_count = in->fd_count; - memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET))); -} - -/* - static void dump_fd_set(struct win_fd_set *s) - { - unsigned int i; - printf("[ "); - for(i=0;i<s->fd_count;++i) - printf("%d ",(int)s->fd_array[i]); - printf("]\n"); - } -*/ - -int -win32_dispatch(struct event_base *base, void *op, - struct timeval *tv) -{ - struct win32op *win32op = op; - int res = 0; - u_int i; - int fd_count; - - fd_set_copy(win32op->readset_out, win32op->readset_in); - fd_set_copy(win32op->exset_out, win32op->readset_in); - fd_set_copy(win32op->writeset_out, win32op->writeset_in); - - fd_count = - (win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ? - win32op->readset_out->fd_count : win32op->writeset_out->fd_count; - - if (!fd_count) { - /* Windows doesn't like you to call select() with no sockets */ - Sleep(timeval_to_ms(tv)); - evsignal_process(base); - return (0); - } - - res = select(fd_count, - (struct fd_set*)win32op->readset_out, - (struct fd_set*)win32op->writeset_out, - (struct fd_set*)win32op->exset_out, tv); - - event_debug(("%s: select returned %d", __func__, res)); - - if(res <= 0) { - evsignal_process(base); - return res; - } else if (base->sig.evsignal_caught) { - evsignal_process(base); - } - - for (i=0; i<win32op->readset_out->fd_count; ++i) { - struct event_entry *ent; - SOCKET s = win32op->readset_out->fd_array[i]; - if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) - event_active(ent->read_event, EV_READ, 1); - } - for (i=0; i<win32op->exset_out->fd_count; ++i) { - struct event_entry *ent; - SOCKET s = win32op->exset_out->fd_array[i]; - if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event) - event_active(ent->read_event, EV_READ, 1); - } - for (i=0; i<win32op->writeset_out->fd_count; ++i) { - struct event_entry *ent; - SOCKET s = win32op->writeset_out->fd_array[i]; - if ((ent = get_event_entry(win32op, s, 0)) && ent->write_event) - event_active(ent->write_event, EV_WRITE, 1); - } - -#if 0 - if (signal_recalc() == -1) - return (-1); -#endif - - return (0); -} - -void -win32_dealloc(struct event_base *_base, void *arg) -{ - struct win32op *win32op = arg; - - evsignal_dealloc(_base); - if (win32op->readset_in) - free(win32op->readset_in); - if (win32op->writeset_in) - free(win32op->writeset_in); - if (win32op->readset_out) - free(win32op->readset_out); - if (win32op->writeset_out) - free(win32op->writeset_out); - if (win32op->exset_out) - free(win32op->exset_out); - /* XXXXX free the tree. */ - - memset(win32op, 0, sizeof(win32op)); - free(win32op); -} - -#if 0 -static void -signal_handler(int sig) -{ - evsigcaught[sig]++; - signal_caught = 1; -} - -int -signal_recalc(void) -{ - struct event *ev; - - /* Reinstall our signal handler. */ - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1) - return (-1); - } - return (0); -} - -void -signal_process(void) -{ - struct event *ev; - short ncalls; - - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - ncalls = evsigcaught[EVENT_SIGNAL(ev)]; - if (ncalls) { - if (!(ev->ev_events & EV_PERSIST)) - event_del(ev); - event_active(ev, EV_SIGNAL, ncalls); - } - } - - memset(evsigcaught, 0, sizeof(evsigcaught)); - signal_caught = 0; -} -#endif - diff --git a/extra/libevent/buffer.c b/extra/libevent/buffer.c deleted file mode 100644 index d3394dae470..00000000000 --- a/extra/libevent/buffer.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#include <winsock2.h> -#include <windows.h> -#endif - -#ifdef HAVE_VASPRINTF -/* If we have vasprintf, we need to define this before we include stdio.h. */ -#define _GNU_SOURCE -#endif - -#include <sys/types.h> - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif - -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "event.h" -#include "config.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; - -#ifndef va_copy -#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) -#endif - va_copy(aq, ap); - -#ifdef WIN32 - sz = _vsnprintf(buffer, space - 1, fmt, aq); - buffer[space - 1] = '\0'; -#else - sz = vsnprintf(buffer, space, fmt, aq); -#endif - - 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 (int)(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 defined(FIONREAD) -#ifdef WIN32 - long lng = (long)n; - if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) { -#else - if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) { -#endif - 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 = (int)(buf->totallen << 2); - if (n < EVBUFFER_MAX_READ) - n = EVBUFFER_MAX_READ; - } -#endif - 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; - -#ifndef WIN32 - n = read(fd, p, howmuch); -#else - n = recv(fd, p, howmuch, 0); -#endif - 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; - -#ifndef WIN32 - n = write(fd, buffer->buffer, buffer->off); -#else - n = send(fd, buffer->buffer, (int)buffer->off, 0); -#endif - if (n == -1) - return (-1); - if (n == 0) - return (0); - evbuffer_drain(buffer, n); - - return (n); -} - -u_char * -evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len) -{ - u_char *search = buffer->buffer, *end = search + buffer->off; - u_char *p; - - while (search < end && - (p = memchr(search, *what, end - search)) != NULL) { - if (p + len > end) - break; - if (memcmp(p, what, len) == 0) - return (p); - search = p + 1; - } - - return (NULL); -} - -void evbuffer_setcb(struct evbuffer *buffer, - void (*cb)(struct evbuffer *, size_t, size_t, void *), - void *cbarg) -{ - buffer->cb = cb; - buffer->cbarg = cbarg; -} diff --git a/extra/libevent/compat/sys/_time.h b/extra/libevent/compat/sys/_time.h deleted file mode 100644 index 8cabb0d55e7..00000000000 --- a/extra/libevent/compat/sys/_time.h +++ /dev/null @@ -1,163 +0,0 @@ -/* $OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $ */ -/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */ - -/* - * Copyright (c) 1982, 1986, 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. - * - * @(#)time.h 8.2 (Berkeley) 7/10/94 - */ - -#ifndef _SYS_TIME_H_ -#define _SYS_TIME_H_ - -#include <sys/types.h> - -/* - * Structure returned by gettimeofday(2) system call, - * and used in other calls. - */ -struct timeval { - long tv_sec; /* seconds */ - long tv_usec; /* and microseconds */ -}; - -/* - * Structure defined by POSIX.1b to be like a timeval. - */ -struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* and nanoseconds */ -}; - -#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ - (ts)->tv_sec = (tv)->tv_sec; \ - (ts)->tv_nsec = (tv)->tv_usec * 1000; \ -} -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ - (tv)->tv_sec = (ts)->tv_sec; \ - (tv)->tv_usec = (ts)->tv_nsec / 1000; \ -} - -struct timezone { - int tz_minuteswest; /* minutes west of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; -#define DST_NONE 0 /* not on dst */ -#define DST_USA 1 /* USA style dst */ -#define DST_AUST 2 /* Australian style dst */ -#define DST_WET 3 /* Western European dst */ -#define DST_MET 4 /* Middle European dst */ -#define DST_EET 5 /* Eastern European dst */ -#define DST_CAN 6 /* Canada */ - -/* Operations on timevals. */ -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define 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 timeradd(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ - if ((vvp)->tv_usec >= 1000000) { \ - (vvp)->tv_sec++; \ - (vvp)->tv_usec -= 1000000; \ - } \ - } while (0) -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) - -/* Operations on timespecs. */ -#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0 -#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec) -#define timespeccmp(tsp, usp, cmp) \ - (((tsp)->tv_sec == (usp)->tv_sec) ? \ - ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ - ((tsp)->tv_sec cmp (usp)->tv_sec)) -#define timespecadd(tsp, usp, vsp) \ - do { \ - (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ - (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ - if ((vsp)->tv_nsec >= 1000000000L) { \ - (vsp)->tv_sec++; \ - (vsp)->tv_nsec -= 1000000000L; \ - } \ - } while (0) -#define timespecsub(tsp, usp, vsp) \ - do { \ - (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ - (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ - if ((vsp)->tv_nsec < 0) { \ - (vsp)->tv_sec--; \ - (vsp)->tv_nsec += 1000000000L; \ - } \ - } while (0) - -/* - * Names of the interval timers, and structure - * defining a timer setting. - */ -#define ITIMER_REAL 0 -#define ITIMER_VIRTUAL 1 -#define ITIMER_PROF 2 - -struct itimerval { - struct timeval it_interval; /* timer interval */ - struct timeval it_value; /* current value */ -}; - -/* - * Getkerninfo clock information structure - */ -struct clockinfo { - int hz; /* clock frequency */ - int tick; /* micro-seconds per hz tick */ - int tickadj; /* clock skew rate for adjtime() */ - int stathz; /* statistics clock frequency */ - int profhz; /* profiling clock frequency */ -}; - -#define CLOCK_REALTIME 0 -#define CLOCK_VIRTUAL 1 -#define CLOCK_PROF 2 - -#define TIMER_RELTIME 0x0 /* relative timer */ -#define TIMER_ABSTIME 0x1 /* absolute timer */ - -/* --- stuff got cut here - niels --- */ - -#endif /* !_SYS_TIME_H_ */ diff --git a/extra/libevent/compat/sys/queue.h b/extra/libevent/compat/sys/queue.h deleted file mode 100644 index c0956ddce43..00000000000 --- a/extra/libevent/compat/sys/queue.h +++ /dev/null @@ -1,488 +0,0 @@ -/* $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $ */ -/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ - -/* - * Copyright (c) 1991, 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. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#ifndef WIN32 -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} -#endif - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = SLIST_FIRST(head); \ - (var) != SLIST_END(head); \ - (var) = SLIST_NEXT(var, field)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) { \ - SLIST_FIRST(head) = SLIST_END(head); \ -} - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (0) - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List access methods - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for((var) = LIST_FIRST(head); \ - (var)!= LIST_END(head); \ - (var) = LIST_NEXT(var, field)) - -/* - * List functions. - */ -#define LIST_INIT(head) do { \ - LIST_FIRST(head) = LIST_END(head); \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (0) - -#define LIST_REMOVE(elm, field) do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ -} while (0) - -#define LIST_REPLACE(elm, elm2, field) do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = \ - &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ -} while (0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (0) - -#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ - if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (0) - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * tail queue access methods - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -/* XXX */ -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) \ - (TAILQ_FIRST(head) == TAILQ_END(head)) - -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) - -#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \ - for((var) = TAILQ_LAST(head, headname); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_PREV(var, headname, field)) - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (0) - -#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) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ - (elm2)->field.tqe_next->field.tqe_prev = \ - &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ -} while (0) - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue access methods - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for((var) = CIRCLEQ_FIRST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_NEXT(var, field)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for((var) = CIRCLEQ_LAST(head); \ - (var) != CIRCLEQ_END(head); \ - (var) = CIRCLEQ_PREV(var, field)) - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (0) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ -} while (0) - -#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ - CIRCLEQ_END(head)) \ - (head).cqh_last = (elm2); \ - else \ - (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ - if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ - CIRCLEQ_END(head)) \ - (head).cqh_first = (elm2); \ - else \ - (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/extra/libevent/compat/sys/tree.h b/extra/libevent/compat/sys/tree.h deleted file mode 100644 index 6a3381caee4..00000000000 --- a/extra/libevent/compat/sys/tree.h +++ /dev/null @@ -1,677 +0,0 @@ -/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ -/* - * Copyright 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. - * - * 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 _SYS_TREE_H_ -#define _SYS_TREE_H_ - -/* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * - * A red-black tree is a binary search tree with the node color as an - * extra attribute. It fulfills a set of conditions: - * - every search path from the root to a leaf consists of the - * same number of black nodes, - * - each red node (except for the root) has a black parent, - * - each leaf node is black. - * - * Every operation on a red-black tree is bounded as O(lg n). - * The maximum height of a red-black tree is 2lg (n+1). - */ - -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while ((__comp = (cmp)(elm, (head)->sph_root))) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ -\ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ - __left = __right = &__node; \ -\ - while (1) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - -/* Macros that define a red-back tree */ -#define RB_HEAD(name, type) \ -struct name { \ - struct type *rbh_root; /* root of the tree */ \ -} - -#define RB_INITIALIZER(root) \ - { NULL } - -#define RB_INIT(root) do { \ - (root)->rbh_root = NULL; \ -} while (0) - -#define RB_BLACK 0 -#define RB_RED 1 -#define RB_ENTRY(type) \ -struct { \ - struct type *rbe_left; /* left element */ \ - struct type *rbe_right; /* right element */ \ - struct type *rbe_parent; /* parent element */ \ - int rbe_color; /* node color */ \ -} - -#define RB_LEFT(elm, field) (elm)->field.rbe_left -#define RB_RIGHT(elm, field) (elm)->field.rbe_right -#define RB_PARENT(elm, field) (elm)->field.rbe_parent -#define RB_COLOR(elm, field) (elm)->field.rbe_color -#define RB_ROOT(head) (head)->rbh_root -#define RB_EMPTY(head) (RB_ROOT(head) == NULL) - -#define RB_SET(elm, parent, field) do { \ - RB_PARENT(elm, field) = parent; \ - RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ - RB_COLOR(elm, field) = RB_RED; \ -} while (0) - -#define RB_SET_BLACKRED(black, red, field) do { \ - RB_COLOR(black, field) = RB_BLACK; \ - RB_COLOR(red, field) = RB_RED; \ -} while (0) - -#ifndef RB_AUGMENT -#define RB_AUGMENT(x) -#endif - -#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ - (tmp) = RB_RIGHT(elm, field); \ - if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ - RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_LEFT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ - (tmp) = RB_LEFT(elm, field); \ - if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ - RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ - } \ - RB_AUGMENT(elm); \ - if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ - if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ - RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ - else \ - RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ - } else \ - (head)->rbh_root = (tmp); \ - RB_RIGHT(tmp, field) = (elm); \ - RB_PARENT(elm, field) = (tmp); \ - RB_AUGMENT(tmp); \ - if ((RB_PARENT(tmp, field))) \ - RB_AUGMENT(RB_PARENT(tmp, field)); \ -} while (0) - -/* Generates prototypes and inline functions */ -#define RB_PROTOTYPE(name, type, field, cmp) \ -void name##_RB_INSERT_COLOR(struct name *, struct type *); \ -void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ -struct type *name##_RB_REMOVE(struct name *, struct type *); \ -struct type *name##_RB_INSERT(struct name *, struct type *); \ -struct type *name##_RB_FIND(struct name *, struct type *); \ -struct type *name##_RB_NEXT(struct type *); \ -struct type *name##_RB_MINMAX(struct name *, int); \ - \ - -/* Main rb operation. - * Moves node close to the key of elm to top - */ -#define RB_GENERATE(name, type, field, cmp) \ -void \ -name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ -{ \ - struct type *parent, *gparent, *tmp; \ - while ((parent = RB_PARENT(elm, field)) && \ - RB_COLOR(parent, field) == RB_RED) { \ - gparent = RB_PARENT(parent, field); \ - if (parent == RB_LEFT(gparent, field)) { \ - tmp = RB_RIGHT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_RIGHT(parent, field) == elm) { \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_RIGHT(head, gparent, tmp, field); \ - } else { \ - tmp = RB_LEFT(gparent, field); \ - if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ - RB_COLOR(tmp, field) = RB_BLACK; \ - RB_SET_BLACKRED(parent, gparent, field);\ - elm = gparent; \ - continue; \ - } \ - if (RB_LEFT(parent, field) == elm) { \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = parent; \ - parent = elm; \ - elm = tmp; \ - } \ - RB_SET_BLACKRED(parent, gparent, field); \ - RB_ROTATE_LEFT(head, gparent, tmp, field); \ - } \ - } \ - RB_COLOR(head->rbh_root, field) = RB_BLACK; \ -} \ - \ -void \ -name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ -{ \ - struct type *tmp; \ - while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ - elm != RB_ROOT(head)) { \ - if (RB_LEFT(parent, field) == elm) { \ - tmp = RB_RIGHT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ - struct type *oleft; \ - if ((oleft = RB_LEFT(tmp, field)))\ - RB_COLOR(oleft, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_RIGHT(head, tmp, oleft, field);\ - tmp = RB_RIGHT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_RIGHT(tmp, field)) \ - RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_LEFT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } else { \ - tmp = RB_LEFT(parent, field); \ - if (RB_COLOR(tmp, field) == RB_RED) { \ - RB_SET_BLACKRED(tmp, parent, field); \ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - if ((RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ - (RB_RIGHT(tmp, field) == NULL || \ - RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ - RB_COLOR(tmp, field) = RB_RED; \ - elm = parent; \ - parent = RB_PARENT(elm, field); \ - } else { \ - if (RB_LEFT(tmp, field) == NULL || \ - RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ - struct type *oright; \ - if ((oright = RB_RIGHT(tmp, field)))\ - RB_COLOR(oright, field) = RB_BLACK;\ - RB_COLOR(tmp, field) = RB_RED; \ - RB_ROTATE_LEFT(head, tmp, oright, field);\ - tmp = RB_LEFT(parent, field); \ - } \ - RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ - RB_COLOR(parent, field) = RB_BLACK; \ - if (RB_LEFT(tmp, field)) \ - RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ - RB_ROTATE_RIGHT(head, parent, tmp, field);\ - elm = RB_ROOT(head); \ - break; \ - } \ - } \ - } \ - if (elm) \ - RB_COLOR(elm, field) = RB_BLACK; \ -} \ - \ -struct type * \ -name##_RB_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *child, *parent, *old = elm; \ - int color; \ - if (RB_LEFT(elm, field) == NULL) \ - child = RB_RIGHT(elm, field); \ - else if (RB_RIGHT(elm, field) == NULL) \ - child = RB_LEFT(elm, field); \ - else { \ - struct type *left; \ - elm = RB_RIGHT(elm, field); \ - while ((left = RB_LEFT(elm, field))) \ - elm = left; \ - child = RB_RIGHT(elm, field); \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ - if (RB_PARENT(elm, field) == old) \ - parent = elm; \ - (elm)->field = (old)->field; \ - if (RB_PARENT(old, field)) { \ - if (RB_LEFT(RB_PARENT(old, field), field) == old)\ - RB_LEFT(RB_PARENT(old, field), field) = elm;\ - else \ - RB_RIGHT(RB_PARENT(old, field), field) = elm;\ - RB_AUGMENT(RB_PARENT(old, field)); \ - } else \ - RB_ROOT(head) = elm; \ - RB_PARENT(RB_LEFT(old, field), field) = elm; \ - if (RB_RIGHT(old, field)) \ - RB_PARENT(RB_RIGHT(old, field), field) = elm; \ - if (parent) { \ - left = parent; \ - do { \ - RB_AUGMENT(left); \ - } while ((left = RB_PARENT(left, field))); \ - } \ - goto color; \ - } \ - parent = RB_PARENT(elm, field); \ - color = RB_COLOR(elm, field); \ - if (child) \ - RB_PARENT(child, field) = parent; \ - if (parent) { \ - if (RB_LEFT(parent, field) == elm) \ - RB_LEFT(parent, field) = child; \ - else \ - RB_RIGHT(parent, field) = child; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = child; \ -color: \ - if (color == RB_BLACK) \ - name##_RB_REMOVE_COLOR(head, parent, child); \ - return (old); \ -} \ - \ -/* Inserts a node into the RB tree */ \ -struct type * \ -name##_RB_INSERT(struct name *head, struct type *elm) \ -{ \ - struct type *tmp; \ - struct type *parent = NULL; \ - int comp = 0; \ - tmp = RB_ROOT(head); \ - while (tmp) { \ - parent = tmp; \ - comp = (cmp)(elm, parent); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - RB_SET(elm, parent, field); \ - if (parent != NULL) { \ - if (comp < 0) \ - RB_LEFT(parent, field) = elm; \ - else \ - RB_RIGHT(parent, field) = elm; \ - RB_AUGMENT(parent); \ - } else \ - RB_ROOT(head) = elm; \ - name##_RB_INSERT_COLOR(head, elm); \ - return (NULL); \ -} \ - \ -/* Finds the node with the same key as elm */ \ -struct type * \ -name##_RB_FIND(struct name *head, struct type *elm) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - int comp; \ - while (tmp) { \ - comp = cmp(elm, tmp); \ - if (comp < 0) \ - tmp = RB_LEFT(tmp, field); \ - else if (comp > 0) \ - tmp = RB_RIGHT(tmp, field); \ - else \ - return (tmp); \ - } \ - return (NULL); \ -} \ - \ -struct type * \ -name##_RB_NEXT(struct type *elm) \ -{ \ - if (RB_RIGHT(elm, field)) { \ - elm = RB_RIGHT(elm, field); \ - while (RB_LEFT(elm, field)) \ - elm = RB_LEFT(elm, field); \ - } else { \ - if (RB_PARENT(elm, field) && \ - (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ - elm = RB_PARENT(elm, field); \ - else { \ - while (RB_PARENT(elm, field) && \ - (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ - elm = RB_PARENT(elm, field); \ - elm = RB_PARENT(elm, field); \ - } \ - } \ - return (elm); \ -} \ - \ -struct type * \ -name##_RB_MINMAX(struct name *head, int val) \ -{ \ - struct type *tmp = RB_ROOT(head); \ - struct type *parent = NULL; \ - while (tmp) { \ - parent = tmp; \ - if (val < 0) \ - tmp = RB_LEFT(tmp, field); \ - else \ - tmp = RB_RIGHT(tmp, field); \ - } \ - return (parent); \ -} - -#define RB_NEGINF -1 -#define RB_INF 1 - -#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) -#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) -#define RB_FIND(name, x, y) name##_RB_FIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) -#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) - -#define RB_FOREACH(x, name, head) \ - for ((x) = RB_MIN(name, head); \ - (x) != NULL; \ - (x) = name##_RB_NEXT(x)) - -#endif /* _SYS_TREE_H_ */ diff --git a/extra/libevent/devpoll.c b/extra/libevent/devpoll.c deleted file mode 100644 index 3a3ec7e64a8..00000000000 --- a/extra/libevent/devpoll.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright 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. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_DEVPOLL - -#include <sys/types.h> -#include <sys/resource.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <sys/_time.h> -#endif -#include <sys/queue.h> -#include <sys/devpoll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <assert.h> - -#include "event.h" -#include "event-internal.h" -#include "evsignal.h" -#include "log.h" - -/* due to limitations in the devpoll interface, we need to keep track of - * all file descriptors outself. - */ -struct evdevpoll { - struct event *evread; - struct event *evwrite; -}; - -struct devpollop { - struct evdevpoll *fds; - int nfds; - struct pollfd *events; - int nevents; - int dpfd; - struct pollfd *changes; - int nchanges; -}; - -static void *devpoll_init (struct event_base *); -static int devpoll_add (void *, struct event *); -static int devpoll_del (void *, struct event *); -static int devpoll_dispatch (struct event_base *, void *, struct timeval *); -static void devpoll_dealloc (struct event_base *, void *); - -struct eventop devpollops = { - "devpoll", - devpoll_init, - devpoll_add, - devpoll_del, - devpoll_dispatch, - devpoll_dealloc, - 1 /* need reinit */ -}; - -#define NEVENT 32000 - -static int -devpoll_commit(struct devpollop *devpollop) -{ - /* - * Due to a bug in Solaris, we have to use pwrite with an offset of 0. - * Write is limited to 2GB of data, until it will fail. - */ - if (pwrite(devpollop->dpfd, devpollop->changes, - sizeof(struct pollfd) * devpollop->nchanges, 0) == -1) - return(-1); - - devpollop->nchanges = 0; - return(0); -} - -static int -devpoll_queue(struct devpollop *devpollop, int fd, int events) { - struct pollfd *pfd; - - if (devpollop->nchanges >= devpollop->nevents) { - /* - * Change buffer is full, must commit it to /dev/poll before - * adding more - */ - if (devpoll_commit(devpollop) != 0) - return(-1); - } - - pfd = &devpollop->changes[devpollop->nchanges++]; - pfd->fd = fd; - pfd->events = events; - pfd->revents = 0; - - return(0); -} - -static void * -devpoll_init(struct event_base *base) -{ - int dpfd, nfiles = NEVENT; - struct rlimit rl; - struct devpollop *devpollop; - - /* Disable devpoll when this environment variable is set */ - if (getenv("EVENT_NODEVPOLL")) - return (NULL); - - if (!(devpollop = calloc(1, sizeof(struct devpollop)))) - return (NULL); - - if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && - (unsigned long long) rl.rlim_cur != (unsigned long long) RLIM_INFINITY) - nfiles = rl.rlim_cur - 1; - - /* Initialize the kernel queue */ - if ((dpfd = open("/dev/poll", O_RDWR)) == -1) { - event_warn("open: /dev/poll"); - free(devpollop); - return (NULL); - } - - devpollop->dpfd = dpfd; - - /* Initialize fields */ - devpollop->events = calloc(nfiles, sizeof(struct pollfd)); - if (devpollop->events == NULL) { - free(devpollop); - close(dpfd); - return (NULL); - } - devpollop->nevents = nfiles; - - devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll)); - if (devpollop->fds == NULL) { - free(devpollop->events); - free(devpollop); - close(dpfd); - return (NULL); - } - devpollop->nfds = nfiles; - - devpollop->changes = calloc(nfiles, sizeof(struct pollfd)); - if (devpollop->changes == NULL) { - free(devpollop->fds); - free(devpollop->events); - free(devpollop); - close(dpfd); - return (NULL); - } - - evsignal_init(base); - - return (devpollop); -} - -static int -devpoll_recalc(struct event_base *base __attribute__((unused)), void *arg, int max) -{ - struct devpollop *devpollop = arg; - - if (max > devpollop->nfds) { - struct evdevpoll *fds; - int nfds; - - nfds = devpollop->nfds; - while (nfds < max) - nfds <<= 1; - - fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll)); - if (fds == NULL) { - event_warn("realloc"); - return (-1); - } - devpollop->fds = fds; - memset(fds + devpollop->nfds, 0, - (nfds - devpollop->nfds) * sizeof(struct evdevpoll)); - devpollop->nfds = nfds; - } - - return (0); -} - -static int -devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) -{ - struct devpollop *devpollop = arg; - struct pollfd *events = devpollop->events; - struct dvpoll dvp; - struct evdevpoll *evdp; - int i, res, timeout = -1; - - if (devpollop->nchanges) - devpoll_commit(devpollop); - - if (tv != NULL) - timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; - - dvp.dp_fds = devpollop->events; - dvp.dp_nfds = devpollop->nevents; - dvp.dp_timeout = timeout; - - res = ioctl(devpollop->dpfd, DP_POLL, &dvp); - - if (res == -1) { - if (errno != EINTR) { - event_warn("ioctl: DP_POLL"); - return (-1); - } - - evsignal_process(base); - return (0); - } else if (base->sig.evsignal_caught) { - evsignal_process(base); - } - - event_debug(("%s: devpoll_wait reports %d", __func__, res)); - - for (i = 0; i < res; i++) { - int which = 0; - int what = events[i].revents; - struct event *evread = NULL, *evwrite = NULL; - - assert(events[i].fd < devpollop->nfds); - evdp = &devpollop->fds[events[i].fd]; - - if (what & POLLHUP) - what |= POLLIN | POLLOUT; - else if (what & POLLERR) - what |= POLLIN | POLLOUT; - - if (what & POLLIN) { - evread = evdp->evread; - which |= EV_READ; - } - - if (what & POLLOUT) { - evwrite = evdp->evwrite; - which |= EV_WRITE; - } - - if (!which) - continue; - - if (evread != NULL && !(evread->ev_events & EV_PERSIST)) - event_del(evread); - if (evwrite != NULL && evwrite != evread && - !(evwrite->ev_events & EV_PERSIST)) - event_del(evwrite); - - if (evread != NULL) - event_active(evread, EV_READ, 1); - if (evwrite != NULL) - event_active(evwrite, EV_WRITE, 1); - } - - return (0); -} - - -static int -devpoll_add(void *arg, struct event *ev) -{ - struct devpollop *devpollop = arg; - struct evdevpoll *evdp; - int fd, events; - - if (ev->ev_events & EV_SIGNAL) - return (evsignal_add(ev)); - - fd = ev->ev_fd; - if (fd >= devpollop->nfds) { - /* Extend the file descriptor array as necessary */ - if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1) - return (-1); - } - evdp = &devpollop->fds[fd]; - - /* - * It's not necessary to OR the existing read/write events that we - * are currently interested in with the new event we are adding. - * The /dev/poll driver ORs any new events with the existing events - * that it has cached for the fd. - */ - - events = 0; - if (ev->ev_events & EV_READ) { - if (evdp->evread && evdp->evread != ev) { - /* There is already a different read event registered */ - return(-1); - } - events |= POLLIN; - } - - if (ev->ev_events & EV_WRITE) { - if (evdp->evwrite && evdp->evwrite != ev) { - /* There is already a different write event registered */ - return(-1); - } - events |= POLLOUT; - } - - if (devpoll_queue(devpollop, fd, events) != 0) - return(-1); - - /* Update events responsible */ - if (ev->ev_events & EV_READ) - evdp->evread = ev; - if (ev->ev_events & EV_WRITE) - evdp->evwrite = ev; - - return (0); -} - -static int -devpoll_del(void *arg, struct event *ev) -{ - struct devpollop *devpollop = arg; - struct evdevpoll *evdp; - int fd, events; - int needwritedelete = 1, needreaddelete = 1; - - if (ev->ev_events & EV_SIGNAL) - return (evsignal_del(ev)); - - fd = ev->ev_fd; - if (fd >= devpollop->nfds) - return (0); - evdp = &devpollop->fds[fd]; - - events = 0; - if (ev->ev_events & EV_READ) - events |= POLLIN; - if (ev->ev_events & EV_WRITE) - events |= POLLOUT; - - /* - * The only way to remove an fd from the /dev/poll monitored set is - * to use POLLREMOVE by itself. This removes ALL events for the fd - * provided so if we care about two events and are only removing one - * we must re-add the other event after POLLREMOVE. - */ - - if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0) - return(-1); - - if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) { - /* - * We're not deleting all events, so we must resubmit the - * event that we are still interested in if one exists. - */ - - if ((events & POLLIN) && evdp->evwrite != NULL) { - /* Deleting read, still care about write */ - devpoll_queue(devpollop, fd, POLLOUT); - needwritedelete = 0; - } else if ((events & POLLOUT) && evdp->evread != NULL) { - /* Deleting write, still care about read */ - devpoll_queue(devpollop, fd, POLLIN); - needreaddelete = 0; - } - } - - if (needreaddelete) - evdp->evread = NULL; - if (needwritedelete) - evdp->evwrite = NULL; - - return (0); -} - -static void -devpoll_dealloc(struct event_base *base, void *arg) -{ - struct devpollop *devpollop = arg; - - evsignal_dealloc(base); - if (devpollop->fds) - free(devpollop->fds); - if (devpollop->events) - free(devpollop->events); - if (devpollop->changes) - free(devpollop->changes); - if (devpollop->dpfd >= 0) - close(devpollop->dpfd); - - memset(devpollop, 0, sizeof(struct devpollop)); - free(devpollop); -} - -#endif /* HAVE_DEVPOLL */ diff --git a/extra/libevent/epoll.c b/extra/libevent/epoll.c deleted file mode 100644 index 93ed5b83aa4..00000000000 --- a/extra/libevent/epoll.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * 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. 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 - -#ifdef HAVE_EPOLL - -#include <stdint.h> -#include <sys/types.h> -#include <sys/resource.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <sys/_time.h> -#endif -#include <sys/queue.h> -#include <sys/epoll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif - -#include "event.h" -#include "event-internal.h" -#include "evsignal.h" -#include "log.h" - -/* due to limitations in the epoll interface, we need to keep track of - * all file descriptors outself. - */ -struct evepoll { - struct event *evread; - struct event *evwrite; -}; - -struct epollop { - struct evepoll *fds; - int nfds; - struct epoll_event *events; - int nevents; - int epfd; -}; - -static void *epoll_init (struct event_base *); -static int epoll_add (void *, struct event *); -static int epoll_del (void *, struct event *); -static int epoll_dispatch (struct event_base *, void *, struct timeval *); -static void epoll_dealloc (struct event_base *, void *); - -struct eventop epollops = { - "epoll", - epoll_init, - epoll_add, - epoll_del, - epoll_dispatch, - epoll_dealloc, - 1 /* need reinit */ -}; - -#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 - -#define NEVENT 32000 - -static void * -epoll_init(struct event_base *base) -{ - int epfd, nfiles = NEVENT; - struct rlimit rl; - struct epollop *epollop; - - /* Disable epollueue when this environment variable is set */ - if (getenv("EVENT_NOEPOLL")) - return (NULL); - - if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && - rl.rlim_cur != RLIM_INFINITY) { - /* - * Solaris is somewhat retarded - it's important to drop - * backwards compatibility when making changes. So, don't - * dare to put rl.rlim_cur here. - */ - nfiles = rl.rlim_cur - 1; - } - - /* Initalize the kernel queue */ - - if ((epfd = epoll_create(nfiles)) == -1) { - event_warn("epoll_create"); - return (NULL); - } - - FD_CLOSEONEXEC(epfd); - - if (!(epollop = calloc(1, sizeof(struct epollop)))) - return (NULL); - - epollop->epfd = epfd; - - /* Initalize fields */ - epollop->events = malloc(nfiles * sizeof(struct epoll_event)); - if (epollop->events == NULL) { - free(epollop); - return (NULL); - } - epollop->nevents = nfiles; - - epollop->fds = calloc(nfiles, sizeof(struct evepoll)); - if (epollop->fds == NULL) { - free(epollop->events); - free(epollop); - return (NULL); - } - epollop->nfds = nfiles; - - evsignal_init(base); - - return (epollop); -} - -static int -epoll_recalc(struct event_base *base __attribute__((unused)), void *arg, - int max) -{ - struct epollop *epollop = arg; - - if (max > epollop->nfds) { - struct evepoll *fds; - int nfds; - - nfds = epollop->nfds; - while (nfds < max) - nfds <<= 1; - - fds = realloc(epollop->fds, nfds * sizeof(struct evepoll)); - if (fds == NULL) { - event_warn("realloc"); - return (-1); - } - epollop->fds = fds; - memset(fds + epollop->nfds, 0, - (nfds - epollop->nfds) * sizeof(struct evepoll)); - epollop->nfds = nfds; - } - - return (0); -} - -static int -epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) -{ - struct epollop *epollop = arg; - struct epoll_event *events = epollop->events; - struct evepoll *evep; - int i, res, timeout = -1; - - if (tv != NULL) - timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; - - res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout); - - if (res == -1) { - if (errno != EINTR) { - event_warn("epoll_wait"); - return (-1); - } - - evsignal_process(base); - return (0); - } else if (base->sig.evsignal_caught) { - evsignal_process(base); - } - - event_debug(("%s: epoll_wait reports %d", __func__, res)); - - for (i = 0; i < res; i++) { - int what = events[i].events; - struct event *evread = NULL, *evwrite = NULL; - - evep = (struct evepoll *)events[i].data.ptr; - - if (what & (EPOLLHUP|EPOLLERR)) { - evread = evep->evread; - evwrite = evep->evwrite; - } else { - if (what & EPOLLIN) { - evread = evep->evread; - } - - if (what & EPOLLOUT) { - evwrite = evep->evwrite; - } - } - - if (!(evread||evwrite)) - continue; - - if (evread != NULL) - event_active(evread, EV_READ, 1); - if (evwrite != NULL) - event_active(evwrite, EV_WRITE, 1); - } - - return (0); -} - - -static int -epoll_add(void *arg, struct event *ev) -{ - struct epollop *epollop = arg; - struct epoll_event epev = {0, {0}}; - struct evepoll *evep; - int fd, op, events; - - if (ev->ev_events & EV_SIGNAL) - return (evsignal_add(ev)); - - fd = ev->ev_fd; - if (fd >= epollop->nfds) { - /* Extent the file descriptor array as necessary */ - if (epoll_recalc(ev->ev_base, epollop, fd) == -1) - return (-1); - } - evep = &epollop->fds[fd]; - op = EPOLL_CTL_ADD; - events = 0; - if (evep->evread != NULL) { - events |= EPOLLIN; - op = EPOLL_CTL_MOD; - } - if (evep->evwrite != NULL) { - events |= EPOLLOUT; - op = EPOLL_CTL_MOD; - } - - if (ev->ev_events & EV_READ) - events |= EPOLLIN; - if (ev->ev_events & EV_WRITE) - events |= EPOLLOUT; - - epev.data.ptr = evep; - epev.events = events; - if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1) - return (-1); - - /* Update events responsible */ - if (ev->ev_events & EV_READ) - evep->evread = ev; - if (ev->ev_events & EV_WRITE) - evep->evwrite = ev; - - return (0); -} - -static int -epoll_del(void *arg, struct event *ev) -{ - struct epollop *epollop = arg; - struct epoll_event epev = {0, {0}}; - struct evepoll *evep; - int fd, events, op; - int needwritedelete = 1, needreaddelete = 1; - - if (ev->ev_events & EV_SIGNAL) - return (evsignal_del(ev)); - - fd = ev->ev_fd; - if (fd >= epollop->nfds) - return (0); - evep = &epollop->fds[fd]; - - op = EPOLL_CTL_DEL; - events = 0; - - if (ev->ev_events & EV_READ) - events |= EPOLLIN; - if (ev->ev_events & EV_WRITE) - events |= EPOLLOUT; - - if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) { - if ((events & EPOLLIN) && evep->evwrite != NULL) { - needwritedelete = 0; - events = EPOLLOUT; - op = EPOLL_CTL_MOD; - } else if ((events & EPOLLOUT) && evep->evread != NULL) { - needreaddelete = 0; - events = EPOLLIN; - op = EPOLL_CTL_MOD; - } - } - - epev.events = events; - epev.data.ptr = evep; - - if (needreaddelete) - evep->evread = NULL; - if (needwritedelete) - evep->evwrite = NULL; - - if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1) - return (-1); - - return (0); -} - -static void -epoll_dealloc(struct event_base *base, void *arg) -{ - struct epollop *epollop = arg; - - evsignal_dealloc(base); - if (epollop->fds) - free(epollop->fds); - if (epollop->events) - free(epollop->events); - if (epollop->epfd >= 0) - close(epollop->epfd); - - memset(epollop, 0, sizeof(struct epollop)); - free(epollop); -} - -#endif /* HAVE_EPOLL */ diff --git a/extra/libevent/epoll_sub.c b/extra/libevent/epoll_sub.c deleted file mode 100644 index 95daac3b276..00000000000 --- a/extra/libevent/epoll_sub.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 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. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_EPOLL - -#include <stdint.h> - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/syscall.h> -#include <sys/epoll.h> -#include <unistd.h> - -int -epoll_create(int size) -{ - return (syscall(__NR_epoll_create, size)); -} - -int -epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) -{ - - return (syscall(__NR_epoll_ctl, epfd, op, fd, event)); -} - -int -epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) -{ - return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout)); -} - -#endif /* HAVE_EPOLL */ diff --git a/extra/libevent/evbuffer.c b/extra/libevent/evbuffer.c deleted file mode 100644 index 97dc40c0e41..00000000000 --- a/extra/libevent/evbuffer.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_STDARG_H -#include <stdarg.h> -#endif - -#ifdef WIN32 -#include <winsock2.h> -#endif - -#include "evutil.h" -#include "event.h" - -/* prototypes */ - -void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t); -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 __attribute__((unused)), 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 = (int)bufev->wm_read.high; - - 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 */ - evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev); - return; - } - - /* 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) { -#ifndef WIN32 -/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not - *set errno. thus this error checking is not portable*/ - if (errno == EAGAIN || - errno == EINTR || - errno == EINPROGRESS) - goto reschedule; - /* error case */ - what |= EVBUFFER_ERROR; - -#else - goto reschedule; -#endif - - } 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); - - bufev->readcb = readcb; - bufev->writecb = writecb; - bufev->errorcb = errorcb; - - bufev->cbarg = 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); -} - -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; -} - -/* - * 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; - - res = event_base_set(base, &bufev->ev_read); - if (res == -1) - return (res); - - res = event_base_set(base, &bufev->ev_write); - return (res); -} diff --git a/extra/libevent/evdns.c b/extra/libevent/evdns.c deleted file mode 100644 index de08a18ca19..00000000000 --- a/extra/libevent/evdns.c +++ /dev/null @@ -1,3150 +0,0 @@ -/* $Id: evdns.c 6979 2006-08-04 18:31:13Z nickm $ */ - -/* The original version of this module was written by Adam Langley; for - * a history of modifications, check out the subversion logs. - * - * When editing this module, try to keep it re-mergeable by Adam. Don't - * reformat the whitespace, add Tor dependencies, or so on. - * - * TODO: - * - Support IPv6 and PTR records. - * - Replace all externally visible magic numbers with #defined constants. - * - Write doccumentation for APIs of all external functions. - */ - -/* Async DNS Library - * Adam Langley <agl@imperialviolet.org> - * http://www.imperialviolet.org/eventdns.html - * Public Domain code - * - * This software is Public Domain. To view a copy of the public domain dedication, - * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to - * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. - * - * I ask and expect, but do not require, that all derivative works contain an - * attribution similar to: - * Parts developed by Adam Langley <agl@imperialviolet.org> - * - * You may wish to replace the word "Parts" with something else depending on - * the amount of original code. - * - * (Derivative works does not include programs which link against, run or include - * the source verbatim in their source distributions) - * - * Version: 0.1b - */ - -#include <sys/types.h> -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#include "misc.h" -#endif - -#ifdef DNS_USE_FTIME_FOR_ID -#include <sys/timeb.h> -#endif - -#ifndef DNS_USE_CPU_CLOCK_FOR_ID -#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID -#ifndef DNS_USE_OPENSSL_FOR_ID -#ifndef DNS_USE_FTIME_FOR_ID -#error Must configure at least one id generation method. -#error Please see the documentation. -#endif -#endif -#endif -#endif - -/* #define _POSIX_C_SOURCE 200507 */ -#define _GNU_SOURCE - -#ifdef DNS_USE_CPU_CLOCK_FOR_ID -#ifdef DNS_USE_OPENSSL_FOR_ID -#error Multiple id options selected -#endif -#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID -#error Multiple id options selected -#endif -#include <time.h> -#endif - -#ifdef DNS_USE_OPENSSL_FOR_ID -#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID -#error Multiple id options selected -#endif -#include <openssl/rand.h> -#endif - -#define _FORTIFY_SOURCE 3 - -#include <string.h> -#include <fcntl.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <limits.h> -#include <sys/stat.h> -#include <ctype.h> -#include <stdio.h> -#include <stdarg.h> - -#include "evdns.h" -#include "evutil.h" -#include "log.h" -#ifdef WIN32 -#include <winsock2.h> -#include <windows.h> -#include <iphlpapi.h> -#include <io.h> -#else -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#endif - -#ifdef HAVE_NETINET_IN6_H -#include <netinet/in6.h> -#endif - -#define EVDNS_LOG_DEBUG 0 -#define EVDNS_LOG_WARN 1 - -#ifndef HOST_NAME_MAX -#define HOST_NAME_MAX 255 -#endif - -#include <stdio.h> - -#undef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) - -#ifdef __USE_ISOC99B -/* libevent doesn't work without this */ -typedef ev_uint8_t u_char; -typedef unsigned int uint; -#endif -#include <event.h> - -#define u64 ev_uint64_t -#define u32 ev_uint32_t -#define u16 ev_uint16_t -#define u8 ev_uint8_t - -#ifdef WIN32 -#define snprintf _snprintf -#define open _open -#define read _read -#define close _close -#define strdup _strdup -#endif - -#define MAX_ADDRS 32 /* maximum number of addresses from a single packet */ -/* which we bother recording */ - -#define TYPE_A EVDNS_TYPE_A -#define TYPE_CNAME 5 -#define TYPE_PTR EVDNS_TYPE_PTR -#define TYPE_AAAA EVDNS_TYPE_AAAA - -#define CLASS_INET EVDNS_CLASS_INET - -struct request { - u8 *request; /* the dns packet data */ - unsigned int request_len; - int reissue_count; - int tx_count; /* the number of times that this packet has been sent */ - unsigned int request_type; /* TYPE_PTR or TYPE_A */ - void *user_pointer; /* the pointer given to us for this request */ - evdns_callback_type user_callback; - struct nameserver *ns; /* the server which we last sent it */ - - /* elements used by the searching code */ - int search_index; - struct search_state *search_state; - char *search_origname; /* needs to be free()ed */ - int search_flags; - - /* these objects are kept in a circular list */ - struct request *next, *prev; - - struct event timeout_event; - - u16 trans_id; /* the transaction id */ - char request_appended; /* true if the request pointer is data which follows this struct */ - char transmit_me; /* needs to be transmitted */ -}; - -#ifndef HAVE_STRUCT_IN6_ADDR -struct in6_addr { - u8 s6_addr[16]; -}; -#endif - -struct reply { - unsigned int type; - unsigned int have_answer; - union { - struct { - u32 addrcount; - u32 addresses[MAX_ADDRS]; - } a; - struct { - u32 addrcount; - struct in6_addr addresses[MAX_ADDRS]; - } aaaa; - struct { - char name[HOST_NAME_MAX]; - } ptr; - } data; -}; - -struct nameserver { - int socket; /* a connected UDP socket */ - u32 address; - int failed_times; /* number of times which we have given this server a chance */ - int timedout; /* number of times in a row a request has timed out */ - struct event event; - /* these objects are kept in a circular list */ - struct nameserver *next, *prev; - struct event timeout_event; /* used to keep the timeout for */ - /* when we next probe this server. */ - /* Valid if state == 0 */ - char state; /* zero if we think that this server is down */ - char choked; /* true if we have an EAGAIN from this server's socket */ - char write_waiting; /* true if we are waiting for EV_WRITE events */ -}; - -static struct request *req_head = NULL, *req_waiting_head = NULL; -static struct nameserver *server_head = NULL; - -/* Represents a local port where we're listening for DNS requests. Right now, */ -/* only UDP is supported. */ -struct evdns_server_port { - int socket; /* socket we use to read queries and write replies. */ - int refcnt; /* reference count. */ - char choked; /* Are we currently blocked from writing? */ - char closing; /* Are we trying to close this port, pending writes? */ - evdns_request_callback_fn_type user_callback; /* Fn to handle requests */ - void *user_data; /* Opaque pointer passed to user_callback */ - struct event event; /* Read/write event */ - /* circular list of replies that we want to write. */ - struct server_request *pending_replies; -}; - -/* Represents part of a reply being built. (That is, a single RR.) */ -struct server_reply_item { - struct server_reply_item *next; /* next item in sequence. */ - char *name; /* name part of the RR */ - u16 type : 16; /* The RR type */ - u16 class : 16; /* The RR class (usually CLASS_INET) */ - u32 ttl; /* The RR TTL */ - char is_name; /* True iff data is a label */ - u16 datalen; /* Length of data; -1 if data is a label */ - void *data; /* The contents of the RR */ -}; - -/* Represents a request that we've received as a DNS server, and holds */ -/* the components of the reply as we're constructing it. */ -struct server_request { - /* Pointers to the next and previous entries on the list of replies */ - /* that we're waiting to write. Only set if we have tried to respond */ - /* and gotten EAGAIN. */ - struct server_request *next_pending; - struct server_request *prev_pending; - - u16 trans_id; /* Transaction id. */ - struct evdns_server_port *port; /* Which port received this request on? */ - struct sockaddr_storage addr; /* Where to send the response */ - socklen_t addrlen; /* length of addr */ - - int n_answer; /* how many answer RRs have been set? */ - int n_authority; /* how many authority RRs have been set? */ - int n_additional; /* how many additional RRs have been set? */ - - struct server_reply_item *answer; /* linked list of answer RRs */ - struct server_reply_item *authority; /* linked list of authority RRs */ - struct server_reply_item *additional; /* linked list of additional RRs */ - - /* Constructed response. Only set once we're ready to send a reply. */ - /* Once this is set, the RR fields are cleared, and no more should be set. */ - char *response; - size_t response_len; - - /* Caller-visible fields: flags, questions. */ - struct evdns_server_request base; -}; - -/* helper macro */ -#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0)) - -/* Given a pointer to an evdns_server_request, get the corresponding */ -/* server_request. */ -#define TO_SERVER_REQUEST(base_ptr) \ - ((struct server_request*) \ - (((char*)(base_ptr) - OFFSET_OF(struct server_request, base)))) - -/* The number of good nameservers that we have */ -static int global_good_nameservers = 0; - -/* inflight requests are contained in the req_head list */ -/* and are actually going out across the network */ -static int global_requests_inflight = 0; -/* requests which aren't inflight are in the waiting list */ -/* and are counted here */ -static int global_requests_waiting = 0; - -static int global_max_requests_inflight = 64; - -static struct timeval global_timeout = {5, 0}; /* 5 seconds */ -static int global_max_reissues = 1; /* a reissue occurs when we get some errors from the server */ -static int global_max_retransmits = 3; /* number of times we'll retransmit a request which timed out */ -/* number of timeouts in a row before we consider this server to be down */ -static int global_max_nameserver_timeout = 3; - -/* These are the timeout values for nameservers. If we find a nameserver is down */ -/* we try to probe it at intervals as given below. Values are in seconds. */ -static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}}; -static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval); - -static struct nameserver *nameserver_pick(void); -static void evdns_request_insert(struct request *req, struct request **head); -static void nameserver_ready_callback(int fd, short events, void *arg); -static int evdns_transmit(void); -static int evdns_request_transmit(struct request *req); -static void nameserver_send_probe(struct nameserver *const ns); -static void search_request_finished(struct request *const); -static int search_try_next(struct request *const req); -static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg); -static void evdns_requests_pump_waiting_queue(void); -static u16 transaction_id_pick(void); -static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr); -static void request_submit(struct request *const req); - -static int server_request_free(struct server_request *req); -static void server_request_free_answers(struct server_request *req); -static void server_port_free(struct evdns_server_port *port); -static void server_port_ready_callback(int fd, short events, void *arg); - -static int strtoint(const char *const str); - -#ifdef WIN32 -static int -last_error(int sock) -{ - int optval, optvallen=sizeof(optval); - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK && sock >= 0) { - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, - &optvallen)) - return err; - if (optval) - return optval; - } - return err; - -} -static int -error_is_eagain(int err) -{ - return err == EAGAIN || err == WSAEWOULDBLOCK; -} -static int -inet_aton(const char *c, struct in_addr *addr) -{ - ev_uint32_t r; - if (strcmp(c, "255.255.255.255") == 0) { - addr->s_addr = 0xffffffffu; - } else { - r = inet_addr(c); - if (r == INADDR_NONE) - return 0; - addr->s_addr = r; - } - return 1; -} -#else -#define last_error(sock) (errno) -#define error_is_eagain(err) ((err) == EAGAIN) -#endif -#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s) - -#define ISSPACE(c) isspace((int)(unsigned char)(c)) -#define ISDIGIT(c) isdigit((int)(unsigned char)(c)) - -static const char * -debug_ntoa(u32 address) -{ - static char buf[32]; - u32 a = ntohl(address); - snprintf(buf, sizeof(buf), "%d.%d.%d.%d", - (int)(u8)((a>>24)&0xff), - (int)(u8)((a>>16)&0xff), - (int)(u8)((a>>8 )&0xff), - (int)(u8)((a )&0xff)); - return buf; -} - -static evdns_debug_log_fn_type evdns_log_fn = NULL; - -void -evdns_set_log_fn(evdns_debug_log_fn_type fn) -{ - evdns_log_fn = fn; -} - -#ifdef __GNUC__ -#define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3))) -#else -#define EVDNS_LOG_CHECK -#endif - -static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK; -static void -_evdns_log(int warn, const char *fmt, ...) -{ - va_list args; - static char buf[512]; - if (!evdns_log_fn) - return; - va_start(args,fmt); -#ifdef WIN32 - _vsnprintf(buf, sizeof(buf), fmt, args); -#else - vsnprintf(buf, sizeof(buf), fmt, args); -#endif - buf[sizeof(buf)-1] = '\0'; - evdns_log_fn(warn, buf); - va_end(args); -} - -#define log _evdns_log - -/* This walks the list of inflight requests to find the */ -/* one with a matching transaction id. Returns NULL on */ -/* failure */ -static struct request * -request_find_from_trans_id(u16 trans_id) { - struct request *req = req_head, *const started_at = req_head; - - if (req) { - do { - if (req->trans_id == trans_id) return req; - req = req->next; - } while (req != started_at); - } - - return NULL; -} - -/* a libevent callback function which is called when a nameserver */ -/* has gone down and we want to test if it has came back to life yet */ -static void -nameserver_prod_callback(int fd, short events, void *arg) { - struct nameserver *const ns = (struct nameserver *) arg; - (void)fd; - (void)events; - - nameserver_send_probe(ns); -} - -/* a libevent callback which is called when a nameserver probe (to see if */ -/* it has come back to life) times out. We increment the count of failed_times */ -/* and wait longer to send the next probe packet. */ -static void -nameserver_probe_failed(struct nameserver *const ns) { - const struct timeval * timeout; - (void) evtimer_del(&ns->timeout_event); - if (ns->state == 1) { - /* This can happen if the nameserver acts in a way which makes us mark */ - /* it as bad and then starts sending good replies. */ - return; - } - - timeout = - &global_nameserver_timeouts[MIN(ns->failed_times, - global_nameserver_timeouts_length - 1)]; - ns->failed_times++; - - evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); - if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) { - log(EVDNS_LOG_WARN, - "Error from libevent when adding timer event for %s", - debug_ntoa(ns->address)); - /* ???? Do more? */ - } -} - -/* called when a nameserver has been deemed to have failed. For example, too */ -/* many packets have timed out etc */ -static void -nameserver_failed(struct nameserver *const ns, const char *msg) { - struct request *req, *started_at; - /* if this nameserver has already been marked as failed */ - /* then don't do anything */ - if (!ns->state) return; - - log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s", - debug_ntoa(ns->address), msg); - global_good_nameservers--; - assert(global_good_nameservers >= 0); - if (global_good_nameservers == 0) { - log(EVDNS_LOG_WARN, "All nameservers have failed"); - } - - ns->state = 0; - ns->failed_times = 1; - - evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); - if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) { - log(EVDNS_LOG_WARN, - "Error from libevent when adding timer event for %s", - debug_ntoa(ns->address)); - /* ???? Do more? */ - } - - /* walk the list of inflight requests to see if any can be reassigned to */ - /* a different server. Requests in the waiting queue don't have a */ - /* nameserver assigned yet */ - - /* if we don't have *any* good nameservers then there's no point */ - /* trying to reassign requests to one */ - if (!global_good_nameservers) return; - - req = req_head; - started_at = req_head; - if (req) { - do { - if (req->tx_count == 0 && req->ns == ns) { - /* still waiting to go out, can be moved */ - /* to another server */ - req->ns = nameserver_pick(); - } - req = req->next; - } while (req != started_at); - } -} - -static void -nameserver_up(struct nameserver *const ns) { - if (ns->state) return; - log(EVDNS_LOG_WARN, "Nameserver %s is back up", - debug_ntoa(ns->address)); - evtimer_del(&ns->timeout_event); - ns->state = 1; - ns->failed_times = 0; - ns->timedout = 0; - global_good_nameservers++; -} - -static void -request_trans_id_set(struct request *const req, const u16 trans_id) { - req->trans_id = trans_id; - *((u16 *) req->request) = htons(trans_id); -} - -/* Called to remove a request from a list and dealloc it. */ -/* head is a pointer to the head of the list it should be */ -/* removed from or NULL if the request isn't in a list. */ -static void -request_finished(struct request *const req, struct request **head) { - if (head) { - if (req->next == req) { - /* only item in the list */ - *head = NULL; - } else { - req->next->prev = req->prev; - req->prev->next = req->next; - if (*head == req) *head = req->next; - } - } - - log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx", - (unsigned long) req); - evtimer_del(&req->timeout_event); - - search_request_finished(req); - global_requests_inflight--; - - if (!req->request_appended) { - /* need to free the request data on it's own */ - free(req->request); - } else { - /* the request data is appended onto the header */ - /* so everything gets free()ed when we: */ - } - - free(req); - - evdns_requests_pump_waiting_queue(); -} - -/* This is called when a server returns a funny error code. */ -/* We try the request again with another server. */ -/* */ -/* return: */ -/* 0 ok */ -/* 1 failed/reissue is pointless */ -static int -request_reissue(struct request *req) { - const struct nameserver *const last_ns = req->ns; - /* the last nameserver should have been marked as failing */ - /* by the caller of this function, therefore pick will try */ - /* not to return it */ - req->ns = nameserver_pick(); - if (req->ns == last_ns) { - /* ... but pick did return it */ - /* not a lot of point in trying again with the */ - /* same server */ - return 1; - } - - req->reissue_count++; - req->tx_count = 0; - req->transmit_me = 1; - - return 0; -} - -/* this function looks for space on the inflight queue and promotes */ -/* requests from the waiting queue if it can. */ -static void -evdns_requests_pump_waiting_queue(void) { - while (global_requests_inflight < global_max_requests_inflight && - global_requests_waiting) { - struct request *req; - /* move a request from the waiting queue to the inflight queue */ - assert(req_waiting_head); - if (req_waiting_head->next == req_waiting_head) { - /* only one item in the queue */ - req = req_waiting_head; - req_waiting_head = NULL; - } else { - req = req_waiting_head; - req->next->prev = req->prev; - req->prev->next = req->next; - req_waiting_head = req->next; - } - - global_requests_waiting--; - global_requests_inflight++; - - req->ns = nameserver_pick(); - request_trans_id_set(req, transaction_id_pick()); - - evdns_request_insert(req, &req_head); - evdns_request_transmit(req); - evdns_transmit(); - } -} - -static void -reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) { - switch (req->request_type) { - case TYPE_A: - if (reply) - req->user_callback(DNS_ERR_NONE, DNS_IPv4_A, - reply->data.a.addrcount, ttl, - reply->data.a.addresses, - req->user_pointer); - else - req->user_callback(err, 0, 0, 0, NULL, req->user_pointer); - return; - case TYPE_PTR: - if (reply) { - char *name = reply->data.ptr.name; - req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl, - &name, req->user_pointer); - } else { - req->user_callback(err, 0, 0, 0, NULL, - req->user_pointer); - } - return; - case TYPE_AAAA: - if (reply) - req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA, - reply->data.aaaa.addrcount, ttl, - reply->data.aaaa.addresses, - req->user_pointer); - else - req->user_callback(err, 0, 0, 0, NULL, req->user_pointer); - return; - } - assert(0); -} - -/* this processes a parsed reply packet */ -static void -reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) { - int error; - static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED}; - - if (flags & 0x020f || !reply || !reply->have_answer) { - /* there was an error */ - if (flags & 0x0200) { - error = DNS_ERR_TRUNCATED; - } else { - u16 error_code = (flags & 0x000f) - 1; - if (error_code > 4) { - error = DNS_ERR_UNKNOWN; - } else { - error = error_codes[error_code]; - } - } - - switch(error) { - case DNS_ERR_NOTIMPL: - case DNS_ERR_REFUSED: - /* we regard these errors as marking a bad nameserver */ - if (req->reissue_count < global_max_reissues) { - char msg[64]; - snprintf(msg, sizeof(msg), "Bad response %d (%s)", - error, evdns_err_to_string(error)); - nameserver_failed(req->ns, msg); - if (!request_reissue(req)) return; - } - break; - case DNS_ERR_SERVERFAILED: - /* rcode 2 (servfailed) sometimes means "we are broken" and - * sometimes (with some binds) means "that request was very - * confusing." Treat this as a timeout, not a failure. - */ - log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; " - "will allow the request to time out.", - debug_ntoa(req->ns->address)); - break; - default: - /* we got a good reply from the nameserver */ - nameserver_up(req->ns); - } - - if (req->search_state && req->request_type != TYPE_PTR) { - /* if we have a list of domains to search in, try the next one */ - if (!search_try_next(req)) { - /* a new request was issued so this request is finished and */ - /* the user callback will be made when that request (or a */ - /* child of it) finishes. */ - request_finished(req, &req_head); - return; - } - } - - /* all else failed. Pass the failure up */ - reply_callback(req, 0, error, NULL); - request_finished(req, &req_head); - } else { - /* all ok, tell the user */ - reply_callback(req, ttl, 0, reply); - nameserver_up(req->ns); - request_finished(req, &req_head); - } -} - -static int -name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { - int name_end = -1; - int j = *idx; - int ptr_count = 0; -#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0) -#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0) -#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0) - - char *cp = name_out; - const char *const end = name_out + name_out_len; - - /* Normally, names are a series of length prefixed strings terminated */ - /* with a length of 0 (the lengths are u8's < 63). */ - /* However, the length can start with a pair of 1 bits and that */ - /* means that the next 14 bits are a pointer within the current */ - /* packet. */ - - for(;;) { - u8 label_len; - if (j >= length) return -1; - GET8(label_len); - if (!label_len) break; - if (label_len & 0xc0) { - u8 ptr_low; - GET8(ptr_low); - if (name_end < 0) name_end = j; - j = (((int)label_len & 0x3f) << 8) + ptr_low; - /* Make sure that the target offset is in-bounds. */ - if (j < 0 || j >= length) return -1; - /* If we've jumped more times than there are characters in the - * message, we must have a loop. */ - if (++ptr_count > length) return -1; - continue; - } - if (label_len > 63) return -1; - if (cp != name_out) { - if (cp + 1 >= end) return -1; - *cp++ = '.'; - } - if (cp + label_len >= end) return -1; - memcpy(cp, packet + j, label_len); - cp += label_len; - j += label_len; - } - if (cp >= end) return -1; - *cp = '\0'; - if (name_end < 0) - *idx = j; - else - *idx = name_end; - return 0; - err: - return -1; -} - -/* parses a raw request from a nameserver */ -static int -reply_parse(u8 *packet, int length) { - int j = 0; /* index into packet */ - u16 _t; /* used by the macros */ - u32 _t32; /* used by the macros */ - char tmp_name[256]; /* used by the macros */ - - u16 trans_id, questions, answers, authority, additional, datalength; - u16 flags = 0; - u32 ttl, ttl_r = 0xffffffff; - struct reply reply; - struct request *req = NULL; - unsigned int i; - - GET16(trans_id); - GET16(flags); - GET16(questions); - GET16(answers); - GET16(authority); - GET16(additional); - (void) authority; /* suppress "unused variable" warnings. */ - (void) additional; /* suppress "unused variable" warnings. */ - - req = request_find_from_trans_id(trans_id); - if (!req) return -1; - - memset(&reply, 0, sizeof(reply)); - - /* If it's not an answer, it doesn't correspond to any request. */ - if (!(flags & 0x8000)) return -1; /* must be an answer */ - if (flags & 0x020f) { - /* there was an error */ - goto err; - } - /* if (!answers) return; */ /* must have an answer of some form */ - - /* This macro skips a name in the DNS reply. */ -#define SKIP_NAME \ - do { tmp_name[0] = '\0'; \ - if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \ - goto err; \ - } while(0); - - reply.type = req->request_type; - - /* skip over each question in the reply */ - for (i = 0; i < questions; ++i) { - /* the question looks like - * <label:name><u16:type><u16:class> - */ - SKIP_NAME; - j += 4; - if (j > length) goto err; - } - - /* now we have the answer section which looks like - * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...> - */ - - for (i = 0; i < answers; ++i) { - u16 type, class; - - SKIP_NAME; - GET16(type); - GET16(class); - GET32(ttl); - GET16(datalength); - - if (type == TYPE_A && class == CLASS_INET) { - int addrcount, addrtocopy; - if (req->request_type != TYPE_A) { - j += datalength; continue; - } - if ((datalength & 3) != 0) /* not an even number of As. */ - goto err; - addrcount = datalength >> 2; - addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount); - - ttl_r = MIN(ttl_r, ttl); - /* we only bother with the first four addresses. */ - if (j + 4*addrtocopy > length) goto err; - memcpy(&reply.data.a.addresses[reply.data.a.addrcount], - packet + j, 4*addrtocopy); - j += 4*addrtocopy; - reply.data.a.addrcount += addrtocopy; - reply.have_answer = 1; - if (reply.data.a.addrcount == MAX_ADDRS) break; - } else if (type == TYPE_PTR && class == CLASS_INET) { - if (req->request_type != TYPE_PTR) { - j += datalength; continue; - } - if (name_parse(packet, length, &j, reply.data.ptr.name, - sizeof(reply.data.ptr.name))<0) - goto err; - ttl_r = MIN(ttl_r, ttl); - reply.have_answer = 1; - break; - } else if (type == TYPE_AAAA && class == CLASS_INET) { - int addrcount, addrtocopy; - if (req->request_type != TYPE_AAAA) { - j += datalength; continue; - } - if ((datalength & 15) != 0) /* not an even number of AAAAs. */ - goto err; - addrcount = datalength >> 4; /* each address is 16 bytes long */ - addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount); - ttl_r = MIN(ttl_r, ttl); - - /* we only bother with the first four addresses. */ - if (j + 16*addrtocopy > length) goto err; - memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount], - packet + j, 16*addrtocopy); - reply.data.aaaa.addrcount += addrtocopy; - j += 16*addrtocopy; - reply.have_answer = 1; - if (reply.data.aaaa.addrcount == MAX_ADDRS) break; - } else { - /* skip over any other type of resource */ - j += datalength; - } - } - - reply_handle(req, flags, ttl_r, &reply); - return 0; - err: - if (req) - reply_handle(req, flags, 0, NULL); - return -1; -} - -/* Parse a raw request (packet,length) sent to a nameserver port (port) from */ -/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */ -/* callback. */ -static int -request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen) -{ - int j = 0; /* index into packet */ - u16 _t; /* used by the macros */ - char tmp_name[256]; /* used by the macros */ - - int i; - u16 trans_id, flags, questions, answers, authority, additional; - struct server_request *server_req = NULL; - - /* Get the header fields */ - GET16(trans_id); - GET16(flags); - GET16(questions); - GET16(answers); - GET16(authority); - GET16(additional); - - if (flags & 0x8000) return -1; /* Must not be an answer. */ - flags &= 0x0110; /* Only RD and CD get preserved. */ - - server_req = malloc(sizeof(struct server_request)); - if (server_req == NULL) return -1; - memset(server_req, 0, sizeof(struct server_request)); - - server_req->trans_id = trans_id; - memcpy(&server_req->addr, addr, addrlen); - server_req->addrlen = addrlen; - - server_req->base.flags = flags; - server_req->base.nquestions = 0; - server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions); - if (server_req->base.questions == NULL) - goto err; - - for (i = 0; i < questions; ++i) { - u16 type, class; - struct evdns_server_question *q; - int namelen; - if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) - goto err; - GET16(type); - GET16(class); - namelen = strlen(tmp_name); - q = malloc(sizeof(struct evdns_server_question) + namelen); - if (!q) - goto err; - q->type = type; - q->dns_question_class = class; - memcpy(q->name, tmp_name, namelen+1); - server_req->base.questions[server_req->base.nquestions++] = q; - } - - /* Ignore answers, authority, and additional. */ - - server_req->port = port; - port->refcnt++; - - /* Only standard queries are supported. */ - if (flags & 0x7800) { - evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL); - return -1; - } - - port->user_callback(&(server_req->base), port->user_data); - - return 0; -err: - if (server_req) { - if (server_req->base.questions) { - for (i = 0; i < server_req->base.nquestions; ++i) - free(server_req->base.questions[i]); - free(server_req->base.questions); - } - free(server_req); - } - return -1; - -#undef SKIP_NAME -#undef GET32 -#undef GET16 -#undef GET8 -} - -static u16 -default_transaction_id_fn(void) -{ - u16 trans_id; -#ifdef DNS_USE_CPU_CLOCK_FOR_ID - struct timespec ts; -#ifdef CLOCK_MONOTONIC - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) -#else - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) -#endif - event_err(1, "clock_gettime"); - trans_id = ts.tv_nsec & 0xffff; -#endif - -#ifdef DNS_USE_FTIME_FOR_ID - struct _timeb tb; - _ftime(&tb); - trans_id = tb.millitm & 0xffff; -#endif - -#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID - struct timeval tv; - gettimeofday(&tv, NULL); - trans_id = tv.tv_usec & 0xffff; -#endif - -#ifdef DNS_USE_OPENSSL_FOR_ID - if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) { - /* in the case that the RAND call fails we back */ - /* down to using gettimeofday. */ - /* - struct timeval tv; - gettimeofday(&tv, NULL); - trans_id = tv.tv_usec & 0xffff; - */ - abort(); - } -#endif - return trans_id; -} - -static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn; - -void -evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)) -{ - if (fn) - trans_id_function = fn; - else - trans_id_function = default_transaction_id_fn; -} - -/* Try to choose a strong transaction id which isn't already in flight */ -static u16 -transaction_id_pick(void) { - for (;;) { - const struct request *req = req_head, *started_at; - u16 trans_id = trans_id_function(); - - if (trans_id == 0xffff) continue; - /* now check to see if that id is already inflight */ - req = started_at = req_head; - if (req) { - do { - if (req->trans_id == trans_id) break; - req = req->next; - } while (req != started_at); - } - /* we didn't find it, so this is a good id */ - if (req == started_at) return trans_id; - } -} - -/* choose a namesever to use. This function will try to ignore */ -/* nameservers which we think are down and load balance across the rest */ -/* by updating the server_head global each time. */ -static struct nameserver * -nameserver_pick(void) { - struct nameserver *started_at = server_head, *picked; - if (!server_head) return NULL; - - /* if we don't have any good nameservers then there's no */ - /* point in trying to find one. */ - if (!global_good_nameservers) { - server_head = server_head->next; - return server_head; - } - - /* remember that nameservers are in a circular list */ - for (;;) { - if (server_head->state) { - /* we think this server is currently good */ - picked = server_head; - server_head = server_head->next; - return picked; - } - - server_head = server_head->next; - if (server_head == started_at) { - /* all the nameservers seem to be down */ - /* so we just return this one and hope for the */ - /* best */ - assert(global_good_nameservers == 0); - picked = server_head; - server_head = server_head->next; - return picked; - } - } -} - -/* this is called when a namesever socket is ready for reading */ -static void -nameserver_read(struct nameserver *ns) { - u8 packet[1500]; - - for (;;) { - const int r = recv(ns->socket, packet, sizeof(packet), 0); - if (r < 0) { - int err = last_error(ns->socket); - if (error_is_eagain(err)) return; - nameserver_failed(ns, strerror(err)); - return; - } - ns->timedout = 0; - reply_parse(packet, r); - } -} - -/* Read a packet from a DNS client on a server port s, parse it, and */ -/* act accordingly. */ -static void -server_port_read(struct evdns_server_port *s) { - u8 packet[1500]; - struct sockaddr_storage addr; - socklen_t addrlen; - int r; - - for (;;) { - addrlen = sizeof(struct sockaddr_storage); - r = recvfrom(s->socket, packet, sizeof(packet), 0, - (struct sockaddr*) &addr, &addrlen); - if (r < 0) { - int err = last_error(s->socket); - if (error_is_eagain(err)) return; - log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.", - strerror(err), err); - return; - } - request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen); - } -} - -/* Try to write all pending replies on a given DNS server port. */ -static void -server_port_flush(struct evdns_server_port *port) -{ - while (port->pending_replies) { - struct server_request *req = port->pending_replies; - int r = sendto(port->socket, req->response, req->response_len, 0, - (struct sockaddr*) &req->addr, req->addrlen); - if (r < 0) { - int err = last_error(port->socket); - if (error_is_eagain(err)) - return; - log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err); - } - if (server_request_free(req)) { - /* we released the last reference to req->port. */ - return; - } - } - - /* We have no more pending requests; stop listening for 'writeable' events. */ - (void) event_del(&port->event); - event_set(&port->event, port->socket, EV_READ | EV_PERSIST, - server_port_ready_callback, port); - if (event_add(&port->event, NULL) < 0) { - log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server."); - /* ???? Do more? */ - } -} - -/* set if we are waiting for the ability to write to this server. */ -/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */ -/* we stop these events. */ -static void -nameserver_write_waiting(struct nameserver *ns, char waiting) { - if (ns->write_waiting == waiting) return; - - ns->write_waiting = waiting; - (void) event_del(&ns->event); - event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST, - nameserver_ready_callback, ns); - if (event_add(&ns->event, NULL) < 0) { - log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s", - debug_ntoa(ns->address)); - /* ???? Do more? */ - } -} - -/* a callback function. Called by libevent when the kernel says that */ -/* a nameserver socket is ready for writing or reading */ -static void -nameserver_ready_callback(int fd, short events, void *arg) { - struct nameserver *ns = (struct nameserver *) arg; - (void)fd; - - if (events & EV_WRITE) { - ns->choked = 0; - if (!evdns_transmit()) { - nameserver_write_waiting(ns, 0); - } - } - if (events & EV_READ) { - nameserver_read(ns); - } -} - -/* a callback function. Called by libevent when the kernel says that */ -/* a server socket is ready for writing or reading. */ -static void -server_port_ready_callback(int fd, short events, void *arg) { - struct evdns_server_port *port = (struct evdns_server_port *) arg; - (void) fd; - - if (events & EV_WRITE) { - port->choked = 0; - server_port_flush(port); - } - if (events & EV_READ) { - server_port_read(port); - } -} - -/* This is an inefficient representation; only use it via the dnslabel_table_* - * functions, so that is can be safely replaced with something smarter later. */ -#define MAX_LABELS 128 -/* Structures used to implement name compression */ -struct dnslabel_entry { char *v; off_t pos; }; -struct dnslabel_table { - int n_labels; /* number of current entries */ - /* map from name to position in message */ - struct dnslabel_entry labels[MAX_LABELS]; -}; - -/* Initialize dnslabel_table. */ -static void -dnslabel_table_init(struct dnslabel_table *table) -{ - table->n_labels = 0; -} - -/* Free all storage held by table, but not the table itself. */ -static void -dnslabel_clear(struct dnslabel_table *table) -{ - int i; - for (i = 0; i < table->n_labels; ++i) - free(table->labels[i].v); - table->n_labels = 0; -} - -/* return the position of the label in the current message, or -1 if the label */ -/* hasn't been used yet. */ -static int -dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label) -{ - int i; - for (i = 0; i < table->n_labels; ++i) { - if (!strcmp(label, table->labels[i].v)) - return table->labels[i].pos; - } - return -1; -} - -/* remember that we've used the label at position pos */ -static int -dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos) -{ - char *v; - int p; - if (table->n_labels == MAX_LABELS) - return (-1); - v = strdup(label); - if (v == NULL) - return (-1); - p = table->n_labels++; - table->labels[p].v = v; - table->labels[p].pos = pos; - - return (0); -} - -/* Converts a string to a length-prefixed set of DNS labels, starting */ -/* at buf[j]. name and buf must not overlap. name_len should be the length */ -/* of name. table is optional, and is used for compression. */ -/* */ -/* Input: abc.def */ -/* Output: <3>abc<3>def<0> */ -/* */ -/* Returns the first index after the encoded name, or negative on error. */ -/* -1 label was > 63 bytes */ -/* -2 name too long to fit in buffer. */ -/* */ -static off_t -dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j, - const char *name, const int name_len, - struct dnslabel_table *table) { - const char *end = name + name_len; - int ref = 0; - u16 _t; - -#define APPEND16(x) do { \ - if (j + 2 > (off_t)buf_len) \ - goto overflow; \ - _t = htons(x); \ - memcpy(buf + j, &_t, 2); \ - j += 2; \ - } while (0) -#define APPEND32(x) do { \ - if (j + 4 > (off_t)buf_len) \ - goto overflow; \ - _t32 = htonl(x); \ - memcpy(buf + j, &_t32, 4); \ - j += 4; \ - } while (0) - - if (name_len > 255) return -2; - - for (;;) { - const char *const start = name; - if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) { - APPEND16(ref | 0xc000); - return j; - } - name = strchr(name, '.'); - if (!name) { - const unsigned int label_len = end - start; - if (label_len > 63) return -1; - if ((size_t)(j+label_len+1) > buf_len) return -2; - if (table) dnslabel_table_add(table, start, j); - buf[j++] = label_len; - - memcpy(buf + j, start, end - start); - j += end - start; - break; - } else { - /* append length of the label. */ - const unsigned int label_len = name - start; - if (label_len > 63) return -1; - if ((size_t)(j+label_len+1) > buf_len) return -2; - if (table) dnslabel_table_add(table, start, j); - buf[j++] = label_len; - - memcpy(buf + j, start, name - start); - j += name - start; - /* hop over the '.' */ - name++; - } - } - - /* the labels must be terminated by a 0. */ - /* It's possible that the name ended in a . */ - /* in which case the zero is already there */ - if (!j || buf[j-1]) buf[j++] = 0; - return j; - overflow: - return (-2); -} - -/* Finds the length of a dns request for a DNS name of the given */ -/* length. The actual request may be smaller than the value returned */ -/* here */ -static int -evdns_request_len(const int name_len) { - return 96 + /* length of the DNS standard header */ - name_len + 2 + - 4; /* space for the resource type */ -} - -/* build a dns request packet into buf. buf should be at least as long */ -/* as evdns_request_len told you it should be. */ -/* */ -/* Returns the amount of space used. Negative on error. */ -static int -evdns_request_data_build(const char *const name, const int name_len, - const u16 trans_id, const u16 type, const u16 class, - u8 *const buf, size_t buf_len) { - off_t j = 0; /* current offset into buf */ - u16 _t; /* used by the macros */ - - APPEND16(trans_id); - APPEND16(0x0100); /* standard query, recusion needed */ - APPEND16(1); /* one question */ - APPEND16(0); /* no answers */ - APPEND16(0); /* no authority */ - APPEND16(0); /* no additional */ - - j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL); - if (j < 0) { - return (int)j; - } - - APPEND16(type); - APPEND16(class); - - return (int)j; - overflow: - return (-1); -} - -/* exported function */ -struct evdns_server_port * -evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data) -{ - struct evdns_server_port *port; - if (!(port = malloc(sizeof(struct evdns_server_port)))) - return NULL; - memset(port, 0, sizeof(struct evdns_server_port)); - - assert(!is_tcp); /* TCP sockets not yet implemented */ - port->socket = socket; - port->refcnt = 1; - port->choked = 0; - port->closing = 0; - port->user_callback = cb; - port->user_data = user_data; - port->pending_replies = NULL; - - event_set(&port->event, port->socket, EV_READ | EV_PERSIST, - server_port_ready_callback, port); - event_add(&port->event, NULL); /* check return. */ - return port; -} - -/* exported function */ -void -evdns_close_server_port(struct evdns_server_port *port) -{ - if (--port->refcnt == 0) - server_port_free(port); - port->closing = 1; -} - -/* exported function */ -int -evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data) -{ - struct server_request *req = TO_SERVER_REQUEST(_req); - struct server_reply_item **itemp, *item; - int *countp; - - if (req->response) /* have we already answered? */ - return (-1); - - switch (section) { - case EVDNS_ANSWER_SECTION: - itemp = &req->answer; - countp = &req->n_answer; - break; - case EVDNS_AUTHORITY_SECTION: - itemp = &req->authority; - countp = &req->n_authority; - break; - case EVDNS_ADDITIONAL_SECTION: - itemp = &req->additional; - countp = &req->n_additional; - break; - default: - return (-1); - } - while (*itemp) { - itemp = &((*itemp)->next); - } - item = malloc(sizeof(struct server_reply_item)); - if (!item) - return -1; - item->next = NULL; - if (!(item->name = strdup(name))) { - free(item); - return -1; - } - item->type = type; - item->dns_question_class = class; - item->ttl = ttl; - item->is_name = is_name != 0; - item->datalen = 0; - item->data = NULL; - if (data) { - if (item->is_name) { - if (!(item->data = strdup(data))) { - free(item->name); - free(item); - return -1; - } - item->datalen = (u16)-1; - } else { - if (!(item->data = malloc(datalen))) { - free(item->name); - free(item); - return -1; - } - item->datalen = datalen; - memcpy(item->data, data, datalen); - } - } - - *itemp = item; - ++(*countp); - return 0; -} - -/* exported function */ -int -evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl) -{ - return evdns_server_request_add_reply( - req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET, - ttl, n*4, 0, addrs); -} - -/* exported function */ -int -evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl) -{ - return evdns_server_request_add_reply( - req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET, - ttl, n*16, 0, addrs); -} - -/* exported function */ -int -evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl) -{ - u32 a; - char buf[32]; - assert(in || inaddr_name); - assert(!(in && inaddr_name)); - if (in) { - a = ntohl(in->s_addr); - snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", - (int)(u8)((a )&0xff), - (int)(u8)((a>>8 )&0xff), - (int)(u8)((a>>16)&0xff), - (int)(u8)((a>>24)&0xff)); - inaddr_name = buf; - } - return evdns_server_request_add_reply( - req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET, - ttl, -1, 1, hostname); -} - -/* exported function */ -int -evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl) -{ - return evdns_server_request_add_reply( - req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET, - ttl, -1, 1, cname); -} - - -static int -evdns_server_request_format_response(struct server_request *req, int err) -{ - unsigned char buf[1500]; - size_t buf_len = sizeof(buf); - off_t j = 0, r; - u16 _t; - u32 _t32; - int i; - u16 flags; - struct dnslabel_table table; - - if (err < 0 || err > 15) return -1; - - /* Set response bit and error code; copy OPCODE and RD fields from - * question; copy RA and AA if set by caller. */ - flags = req->base.flags; - flags |= (0x8000 | err); - - dnslabel_table_init(&table); - APPEND16(req->trans_id); - APPEND16(flags); - APPEND16(req->base.nquestions); - APPEND16(req->n_answer); - APPEND16(req->n_authority); - APPEND16(req->n_additional); - - /* Add questions. */ - for (i=0; i < req->base.nquestions; ++i) { - const char *s = req->base.questions[i]->name; - j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table); - if (j < 0) { - dnslabel_clear(&table); - return (int) j; - } - APPEND16(req->base.questions[i]->type); - APPEND16(req->base.questions[i]->dns_question_class); - } - - /* Add answer, authority, and additional sections. */ - for (i=0; i<3; ++i) { - struct server_reply_item *item; - if (i==0) - item = req->answer; - else if (i==1) - item = req->authority; - else - item = req->additional; - while (item) { - r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table); - if (r < 0) - goto overflow; - j = r; - - APPEND16(item->type); - APPEND16(item->dns_question_class); - APPEND32(item->ttl); - if (item->is_name) { - off_t len_idx = j, name_start; - j += 2; - name_start = j; - r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table); - if (r < 0) - goto overflow; - j = r; - _t = htons( (short) (j-name_start) ); - memcpy(buf+len_idx, &_t, 2); - } else { - APPEND16(item->datalen); - if (j+item->datalen > (off_t)buf_len) - goto overflow; - memcpy(buf+j, item->data, item->datalen); - j += item->datalen; - } - item = item->next; - } - } - - if (j > 512) { -overflow: - j = 512; - buf[3] |= 0x02; /* set the truncated bit. */ - } - - req->response_len = j; - - if (!(req->response = malloc(req->response_len))) { - server_request_free_answers(req); - dnslabel_clear(&table); - return (-1); - } - memcpy(req->response, buf, req->response_len); - server_request_free_answers(req); - dnslabel_clear(&table); - return (0); -} - -/* exported function */ -int -evdns_server_request_respond(struct evdns_server_request *_req, int err) -{ - struct server_request *req = TO_SERVER_REQUEST(_req); - struct evdns_server_port *port = req->port; - int r; - if (!req->response) { - if ((r = evdns_server_request_format_response(req, err))<0) - return r; - } - - r = sendto(port->socket, req->response, req->response_len, 0, - (struct sockaddr*) &req->addr, req->addrlen); - if (r<0) { - int sock_err = last_error(port->socket); - if (! error_is_eagain(sock_err)) - return -1; - - if (port->pending_replies) { - req->prev_pending = port->pending_replies->prev_pending; - req->next_pending = port->pending_replies; - req->prev_pending->next_pending = - req->next_pending->prev_pending = req; - } else { - req->prev_pending = req->next_pending = req; - port->pending_replies = req; - port->choked = 1; - - (void) event_del(&port->event); - event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port); - - if (event_add(&port->event, NULL) < 0) { - log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server"); - } - - } - - return 1; - } - if (server_request_free(req)) - return 0; - - if (port->pending_replies) - server_port_flush(port); - - return 0; -} - -/* Free all storage held by RRs in req. */ -static void -server_request_free_answers(struct server_request *req) -{ - struct server_reply_item *victim, *next, **list; - int i; - for (i = 0; i < 3; ++i) { - if (i==0) - list = &req->answer; - else if (i==1) - list = &req->authority; - else - list = &req->additional; - - victim = *list; - while (victim) { - next = victim->next; - free(victim->name); - if (victim->data) - free(victim->data); - free(victim); - victim = next; - } - *list = NULL; - } -} - -/* Free all storage held by req, and remove links to it. */ -/* return true iff we just wound up freeing the server_port. */ -static int -server_request_free(struct server_request *req) -{ - int i, rc=1; - if (req->base.questions) { - for (i = 0; i < req->base.nquestions; ++i) - free(req->base.questions[i]); - free(req->base.questions); - } - - if (req->port) { - if (req->port->pending_replies == req) { - if (req->next_pending) - req->port->pending_replies = req->next_pending; - else - req->port->pending_replies = NULL; - } - rc = --req->port->refcnt; - } - - if (req->response) { - free(req->response); - } - - server_request_free_answers(req); - - if (req->next_pending && req->next_pending != req) { - req->next_pending->prev_pending = req->prev_pending; - req->prev_pending->next_pending = req->next_pending; - } - - if (rc == 0) { - server_port_free(req->port); - free(req); - return (1); - } - free(req); - return (0); -} - -/* Free all storage held by an evdns_server_port. Only called when */ -static void -server_port_free(struct evdns_server_port *port) -{ - assert(port); - assert(!port->refcnt); - assert(!port->pending_replies); - if (port->socket > 0) { - CLOSE_SOCKET(port->socket); - port->socket = -1; - } - (void) event_del(&port->event); - /* XXXX actually free the port? -NM */ -} - -/* exported function */ -int -evdns_server_request_drop(struct evdns_server_request *_req) -{ - struct server_request *req = TO_SERVER_REQUEST(_req); - server_request_free(req); - return 0; -} - -/* exported function */ -int -evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len) -{ - struct server_request *req = TO_SERVER_REQUEST(_req); - if (addr_len < (int)req->addrlen) - return -1; - memcpy(sa, &(req->addr), req->addrlen); - return req->addrlen; -} - -#undef APPEND16 -#undef APPEND32 - -/* this is a libevent callback function which is called when a request */ -/* has timed out. */ -static void -evdns_request_timeout_callback(int fd, short events, void *arg) { - struct request *const req = (struct request *) arg; - (void) fd; - (void) events; - - log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg); - - req->ns->timedout++; - if (req->ns->timedout > global_max_nameserver_timeout) { - req->ns->timedout = 0; - nameserver_failed(req->ns, "request timed out."); - } - - (void) evtimer_del(&req->timeout_event); - if (req->tx_count >= global_max_retransmits) { - /* this request has failed */ - reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL); - request_finished(req, &req_head); - } else { - /* retransmit it */ - evdns_request_transmit(req); - } -} - -/* try to send a request to a given server. */ -/* */ -/* return: */ -/* 0 ok */ -/* 1 temporary failure */ -/* 2 other failure */ -static int -evdns_request_transmit_to(struct request *req, struct nameserver *server) { - const int r = send(server->socket, req->request, req->request_len, 0); - if (r < 0) { - int err = last_error(server->socket); - if (error_is_eagain(err)) return 1; - nameserver_failed(req->ns, strerror(err)); - return 2; - } else if (r != (int)req->request_len) { - return 1; /* short write */ - } else { - return 0; - } -} - -/* try to send a request, updating the fields of the request */ -/* as needed */ -/* */ -/* return: */ -/* 0 ok */ -/* 1 failed */ -static int -evdns_request_transmit(struct request *req) { - int retcode = 0, r; - - /* if we fail to send this packet then this flag marks it */ - /* for evdns_transmit */ - req->transmit_me = 1; - if (req->trans_id == 0xffff) abort(); - - if (req->ns->choked) { - /* don't bother trying to write to a socket */ - /* which we have had EAGAIN from */ - return 1; - } - - r = evdns_request_transmit_to(req, req->ns); - switch (r) { - case 1: - /* temp failure */ - req->ns->choked = 1; - nameserver_write_waiting(req->ns, 1); - return 1; - case 2: - /* failed in some other way */ - retcode = 1; - /* fall through */ - default: - /* all ok */ - log(EVDNS_LOG_DEBUG, - "Setting timeout for request %lx", (unsigned long) req); - evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req); - if (evtimer_add(&req->timeout_event, &global_timeout) < 0) { - log(EVDNS_LOG_WARN, - "Error from libevent when adding timer for request %lx", - (unsigned long) req); - /* ???? Do more? */ - } - req->tx_count++; - req->transmit_me = 0; - return retcode; - } -} - -static void -nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) { - struct nameserver *const ns = (struct nameserver *) arg; - (void) type; - (void) count; - (void) ttl; - (void) addresses; - - if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) { - /* this is a good reply */ - nameserver_up(ns); - } else nameserver_probe_failed(ns); -} - -static void -nameserver_send_probe(struct nameserver *const ns) { - struct request *req; - /* here we need to send a probe to a given nameserver */ - /* in the hope that it is up now. */ - - log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address)); - - req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns); - if (!req) return; - /* we force this into the inflight queue no matter what */ - request_trans_id_set(req, transaction_id_pick()); - req->ns = ns; - request_submit(req); -} - -/* returns: */ -/* 0 didn't try to transmit anything */ -/* 1 tried to transmit something */ -static int -evdns_transmit(void) { - char did_try_to_transmit = 0; - - if (req_head) { - struct request *const started_at = req_head, *req = req_head; - /* first transmit all the requests which are currently waiting */ - do { - if (req->transmit_me) { - did_try_to_transmit = 1; - evdns_request_transmit(req); - } - - req = req->next; - } while (req != started_at); - } - - return did_try_to_transmit; -} - -/* exported function */ -int -evdns_count_nameservers(void) -{ - const struct nameserver *server = server_head; - int n = 0; - if (!server) - return 0; - do { - ++n; - server = server->next; - } while (server != server_head); - return n; -} - -/* exported function */ -int -evdns_clear_nameservers_and_suspend(void) -{ - struct nameserver *server = server_head, *started_at = server_head; - struct request *req = req_head, *req_started_at = req_head; - - if (!server) - return 0; - while (1) { - struct nameserver *next = server->next; - (void) event_del(&server->event); - if (evtimer_initialized(&server->timeout_event)) - (void) evtimer_del(&server->timeout_event); - if (server->socket >= 0) - CLOSE_SOCKET(server->socket); - free(server); - if (next == started_at) - break; - server = next; - } - server_head = NULL; - global_good_nameservers = 0; - - while (req) { - struct request *next = req->next; - req->tx_count = req->reissue_count = 0; - req->ns = NULL; - /* ???? What to do about searches? */ - (void) evtimer_del(&req->timeout_event); - req->trans_id = 0; - req->transmit_me = 0; - - global_requests_waiting++; - evdns_request_insert(req, &req_waiting_head); - /* We want to insert these suspended elements at the front of - * the waiting queue, since they were pending before any of - * the waiting entries were added. This is a circular list, - * so we can just shift the start back by one.*/ - req_waiting_head = req_waiting_head->prev; - - if (next == req_started_at) - break; - req = next; - } - req_head = NULL; - global_requests_inflight = 0; - - return 0; -} - - -/* exported function */ -int -evdns_resume(void) -{ - evdns_requests_pump_waiting_queue(); - return 0; -} - -static int -_evdns_nameserver_add_impl(unsigned long int address, int port) { - /* first check to see if we already have this nameserver */ - - const struct nameserver *server = server_head, *const started_at = server_head; - struct nameserver *ns; - struct sockaddr_in sin; - int err = 0; - if (server) { - do { - if (server->address == address) return 3; - server = server->next; - } while (server != started_at); - } - - ns = (struct nameserver *) malloc(sizeof(struct nameserver)); - if (!ns) return -1; - - memset(ns, 0, sizeof(struct nameserver)); - - ns->socket = socket(PF_INET, SOCK_DGRAM, 0); - if (ns->socket < 0) { err = 1; goto out1; } - evutil_make_socket_nonblocking(ns->socket); - sin.sin_addr.s_addr = address; - sin.sin_port = htons(port); - sin.sin_family = AF_INET; - if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) { - err = 2; - goto out2; - } - - ns->address = address; - ns->state = 1; - event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns); - if (event_add(&ns->event, NULL) < 0) { - err = 2; - goto out2; - } - - log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address)); - - /* insert this nameserver into the list of them */ - if (!server_head) { - ns->next = ns->prev = ns; - server_head = ns; - } else { - ns->next = server_head->next; - ns->prev = server_head; - server_head->next = ns; - if (server_head->prev == server_head) { - server_head->prev = ns; - } - } - - global_good_nameservers++; - - return 0; - -out2: - CLOSE_SOCKET(ns->socket); -out1: - free(ns); - log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err); - return err; -} - -/* exported function */ -int -evdns_nameserver_add(unsigned long int address) { - return _evdns_nameserver_add_impl(address, 53); -} - -/* exported function */ -int -evdns_nameserver_ip_add(const char *ip_as_string) { - struct in_addr ina; - int port; - char buf[20]; - const char *cp; - cp = strchr(ip_as_string, ':'); - if (! cp) { - cp = ip_as_string; - port = 53; - } else { - port = strtoint(cp+1); - if (port < 0 || port > 65535) { - return 4; - } - if ((cp-ip_as_string) >= (int)sizeof(buf)) { - return 4; - } - memcpy(buf, ip_as_string, cp-ip_as_string); - buf[cp-ip_as_string] = '\0'; - cp = buf; - } - if (!inet_aton(cp, &ina)) { - return 4; - } - return _evdns_nameserver_add_impl(ina.s_addr, port); -} - -/* insert into the tail of the queue */ -static void -evdns_request_insert(struct request *req, struct request **head) { - if (!*head) { - *head = req; - req->next = req->prev = req; - return; - } - - req->prev = (*head)->prev; - req->prev->next = req; - req->next = *head; - (*head)->prev = req; -} - -static int -string_num_dots(const char *s) { - int count = 0; - while ((s = strchr(s, '.'))) { - s++; - count++; - } - return count; -} - -static struct request * -request_new(int type, const char *name, int flags, - evdns_callback_type callback, void *user_ptr) { - const char issuing_now = - (global_requests_inflight < global_max_requests_inflight) ? 1 : 0; - - const int name_len = strlen(name); - const int request_max_len = evdns_request_len(name_len); - const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff; - /* the request data is alloced in a single block with the header */ - struct request *const req = - (struct request *) malloc(sizeof(struct request) + request_max_len); - int rlen; - (void) flags; - - if (!req) return NULL; - memset(req, 0, sizeof(struct request)); - - /* request data lives just after the header */ - req->request = ((u8 *) req) + sizeof(struct request); - /* denotes that the request data shouldn't be free()ed */ - req->request_appended = 1; - rlen = evdns_request_data_build(name, name_len, trans_id, - type, CLASS_INET, req->request, request_max_len); - if (rlen < 0) - goto err1; - req->request_len = rlen; - req->trans_id = trans_id; - req->tx_count = 0; - req->request_type = type; - req->user_pointer = user_ptr; - req->user_callback = callback; - req->ns = issuing_now ? nameserver_pick() : NULL; - req->next = req->prev = NULL; - - return req; -err1: - free(req); - return NULL; -} - -static void -request_submit(struct request *const req) { - if (req->ns) { - /* if it has a nameserver assigned then this is going */ - /* straight into the inflight queue */ - evdns_request_insert(req, &req_head); - global_requests_inflight++; - evdns_request_transmit(req); - } else { - evdns_request_insert(req, &req_waiting_head); - global_requests_waiting++; - } -} - -/* exported function */ -int evdns_resolve_ipv4(const char *name, int flags, - evdns_callback_type callback, void *ptr) { - log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); - if (flags & DNS_QUERY_NO_SEARCH) { - struct request *const req = - request_new(TYPE_A, name, flags, callback, ptr); - if (req == NULL) - return (1); - request_submit(req); - return (0); - } else { - return (search_request_new(TYPE_A, name, flags, callback, ptr)); - } -} - -/* exported function */ -int evdns_resolve_ipv6(const char *name, int flags, - evdns_callback_type callback, void *ptr) { - log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name); - if (flags & DNS_QUERY_NO_SEARCH) { - struct request *const req = - request_new(TYPE_AAAA, name, flags, callback, ptr); - if (req == NULL) - return (1); - request_submit(req); - return (0); - } else { - return (search_request_new(TYPE_AAAA, name, flags, callback, ptr)); - } -} - -int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { - char buf[32]; - struct request *req; - u32 a; - assert(in); - a = ntohl(in->s_addr); - snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa", - (int)(u8)((a )&0xff), - (int)(u8)((a>>8 )&0xff), - (int)(u8)((a>>16)&0xff), - (int)(u8)((a>>24)&0xff)); - log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); - req = request_new(TYPE_PTR, buf, flags, callback, ptr); - if (!req) return 1; - request_submit(req); - return 0; -} - -int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { - /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */ - char buf[73]; - char *cp; - struct request *req; - int i; - assert(in); - cp = buf; - for (i=15; i >= 0; --i) { - u8 byte = in->s6_addr[i]; - *cp++ = "0123456789abcdef"[byte & 0x0f]; - *cp++ = '.'; - *cp++ = "0123456789abcdef"[byte >> 4]; - *cp++ = '.'; - } - assert(cp + strlen("ip6.arpa") < buf+sizeof(buf)); - memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1); - log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf); - req = request_new(TYPE_PTR, buf, flags, callback, ptr); - if (!req) return 1; - request_submit(req); - return 0; -} - -/*/////////////////////////////////////////////////////////////////// */ -/* Search support */ -/* */ -/* the libc resolver has support for searching a number of domains */ -/* to find a name. If nothing else then it takes the single domain */ -/* from the gethostname() call. */ -/* */ -/* It can also be configured via the domain and search options in a */ -/* resolv.conf. */ -/* */ -/* The ndots option controls how many dots it takes for the resolver */ -/* to decide that a name is non-local and so try a raw lookup first. */ - -struct search_domain { - int len; - struct search_domain *next; - /* the text string is appended to this structure */ -}; - -struct search_state { - int refcount; - int ndots; - int num_domains; - struct search_domain *head; -}; - -static struct search_state *global_search_state = NULL; - -static void -search_state_decref(struct search_state *const state) { - if (!state) return; - state->refcount--; - if (!state->refcount) { - struct search_domain *next, *dom; - for (dom = state->head; dom; dom = next) { - next = dom->next; - free(dom); - } - free(state); - } -} - -static struct search_state * -search_state_new(void) { - struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state)); - if (!state) return NULL; - memset(state, 0, sizeof(struct search_state)); - state->refcount = 1; - state->ndots = 1; - - return state; -} - -static void -search_postfix_clear(void) { - search_state_decref(global_search_state); - - global_search_state = search_state_new(); -} - -/* exported function */ -void -evdns_search_clear(void) { - search_postfix_clear(); -} - -static void -search_postfix_add(const char *domain) { - int domain_len; - struct search_domain *sdomain; - while (domain[0] == '.') domain++; - domain_len = strlen(domain); - - if (!global_search_state) global_search_state = search_state_new(); - if (!global_search_state) return; - global_search_state->num_domains++; - - sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len); - if (!sdomain) return; - memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len); - sdomain->next = global_search_state->head; - sdomain->len = domain_len; - - global_search_state->head = sdomain; -} - -/* reverse the order of members in the postfix list. This is needed because, */ -/* when parsing resolv.conf we push elements in the wrong order */ -static void -search_reverse(void) { - struct search_domain *cur, *prev = NULL, *next; - cur = global_search_state->head; - while (cur) { - next = cur->next; - cur->next = prev; - prev = cur; - cur = next; - } - - global_search_state->head = prev; -} - -/* exported function */ -void -evdns_search_add(const char *domain) { - search_postfix_add(domain); -} - -/* exported function */ -void -evdns_search_ndots_set(const int ndots) { - if (!global_search_state) global_search_state = search_state_new(); - if (!global_search_state) return; - global_search_state->ndots = ndots; -} - -static void -search_set_from_hostname(void) { - char hostname[HOST_NAME_MAX + 1], *domainname; - - search_postfix_clear(); - if (gethostname(hostname, sizeof(hostname))) return; - domainname = strchr(hostname, '.'); - if (!domainname) return; - search_postfix_add(domainname); -} - -/* warning: returns malloced string */ -static char * -search_make_new(const struct search_state *const state, int n, const char *const base_name) { - const int base_len = strlen(base_name); - const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1; - struct search_domain *dom; - - for (dom = state->head; dom; dom = dom->next) { - if (!n--) { - /* this is the postfix we want */ - /* the actual postfix string is kept at the end of the structure */ - const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain); - const int postfix_len = dom->len; - char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1); - if (!newname) return NULL; - memcpy(newname, base_name, base_len); - if (need_to_append_dot) newname[base_len] = '.'; - memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len); - newname[base_len + need_to_append_dot + postfix_len] = 0; - return newname; - } - } - - /* we ran off the end of the list and still didn't find the requested string */ - abort(); - return NULL; /* unreachable; stops warnings in some compilers. */ -} - -static int -search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) { - assert(type == TYPE_A || type == TYPE_AAAA); - if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) && - global_search_state && - global_search_state->num_domains) { - /* we have some domains to search */ - struct request *req; - if (string_num_dots(name) >= global_search_state->ndots) { - req = request_new(type, name, flags, user_callback, user_arg); - if (!req) return 1; - req->search_index = -1; - } else { - char *const new_name = search_make_new(global_search_state, 0, name); - if (!new_name) return 1; - req = request_new(type, new_name, flags, user_callback, user_arg); - free(new_name); - if (!req) return 1; - req->search_index = 0; - } - req->search_origname = strdup(name); - req->search_state = global_search_state; - req->search_flags = flags; - global_search_state->refcount++; - request_submit(req); - return 0; - } else { - struct request *const req = request_new(type, name, flags, user_callback, user_arg); - if (!req) return 1; - request_submit(req); - return 0; - } -} - -/* this is called when a request has failed to find a name. We need to check */ -/* if it is part of a search and, if so, try the next name in the list */ -/* returns: */ -/* 0 another request has been submitted */ -/* 1 no more requests needed */ -static int -search_try_next(struct request *const req) { - if (req->search_state) { - /* it is part of a search */ - char *new_name; - struct request *newreq; - req->search_index++; - if (req->search_index >= req->search_state->num_domains) { - /* no more postfixes to try, however we may need to try */ - /* this name without a postfix */ - if (string_num_dots(req->search_origname) < req->search_state->ndots) { - /* yep, we need to try it raw */ - newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer); - log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname); - if (newreq) { - request_submit(newreq); - return 0; - } - } - return 1; - } - - new_name = search_make_new(req->search_state, req->search_index, req->search_origname); - if (!new_name) return 1; - log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index); - newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer); - free(new_name); - if (!newreq) return 1; - newreq->search_origname = req->search_origname; - req->search_origname = NULL; - newreq->search_state = req->search_state; - newreq->search_flags = req->search_flags; - newreq->search_index = req->search_index; - newreq->search_state->refcount++; - request_submit(newreq); - return 0; - } - return 1; -} - -static void -search_request_finished(struct request *const req) { - if (req->search_state) { - search_state_decref(req->search_state); - req->search_state = NULL; - } - if (req->search_origname) { - free(req->search_origname); - req->search_origname = NULL; - } -} - -/*/////////////////////////////////////////////////////////////////// */ -/* Parsing resolv.conf files */ - -static void -evdns_resolv_set_defaults(int flags) { - /* if the file isn't found then we assume a local resolver */ - if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(); - if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1"); -} - -#ifndef HAVE_STRTOK_R -static char * -strtok_r(char *s, const char *delim, char **state) { - return strtok(s, delim); -} -#endif - -/* helper version of atoi which returns -1 on error */ -static int -strtoint(const char *const str) { - char *endptr; - const int r = strtol(str, &endptr, 10); - if (*endptr) return -1; - return r; -} - -/* helper version of atoi that returns -1 on error and clips to bounds. */ -static int -strtoint_clipped(const char *const str, int min, int max) -{ - int r = strtoint(str); - if (r == -1) - return r; - else if (r<min) - return min; - else if (r>max) - return max; - else - return r; -} - -/* exported function */ -int -evdns_set_option(const char *option, const char *val, int flags) -{ - if (!strncmp(option, "ndots:", 6)) { - const int ndots = strtoint(val); - if (ndots == -1) return -1; - if (!(flags & DNS_OPTION_SEARCH)) return 0; - log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots); - if (!global_search_state) global_search_state = search_state_new(); - if (!global_search_state) return -1; - global_search_state->ndots = ndots; - } else if (!strncmp(option, "timeout:", 8)) { - const int timeout = strtoint(val); - if (timeout == -1) return -1; - if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout); - global_timeout.tv_sec = timeout; - } else if (!strncmp(option, "max-timeouts:", 12)) { - const int maxtimeout = strtoint_clipped(val, 1, 255); - if (maxtimeout == -1) return -1; - if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d", - maxtimeout); - global_max_nameserver_timeout = maxtimeout; - } else if (!strncmp(option, "max-inflight:", 13)) { - const int maxinflight = strtoint_clipped(val, 1, 65000); - if (maxinflight == -1) return -1; - if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d", - maxinflight); - global_max_requests_inflight = maxinflight; - } else if (!strncmp(option, "attempts:", 9)) { - int retries = strtoint(val); - if (retries == -1) return -1; - if (retries > 255) retries = 255; - if (!(flags & DNS_OPTION_MISC)) return 0; - log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries); - global_max_retransmits = retries; - } - return 0; -} - -static void -resolv_conf_parse_line(char *const start, int flags) { - char *strtok_state; - static const char *const delims = " \t"; -#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state) - - char *const first_token = strtok_r(start, delims, &strtok_state); - if (!first_token) return; - - if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) { - const char *const nameserver = NEXT_TOKEN; - struct in_addr ina; - - if (inet_aton(nameserver, &ina)) { - /* address is valid */ - evdns_nameserver_add(ina.s_addr); - } - } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) { - const char *const domain = NEXT_TOKEN; - if (domain) { - search_postfix_clear(); - search_postfix_add(domain); - } - } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) { - const char *domain; - search_postfix_clear(); - - while ((domain = NEXT_TOKEN)) { - search_postfix_add(domain); - } - search_reverse(); - } else if (!strcmp(first_token, "options")) { - const char *option; - while ((option = NEXT_TOKEN)) { - const char *val = strchr(option, ':'); - evdns_set_option(option, val ? val+1 : "", flags); - } - } -#undef NEXT_TOKEN -} - -/* exported function */ -/* returns: */ -/* 0 no errors */ -/* 1 failed to open file */ -/* 2 failed to stat file */ -/* 3 file too large */ -/* 4 out of memory */ -/* 5 short read from file */ -int -evdns_resolv_conf_parse(int flags, const char *const filename) { - struct stat st; - int fd, n, r; - u8 *resolv; - char *start; - int err = 0; - - log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); - - fd = open(filename, O_RDONLY); - if (fd < 0) { - evdns_resolv_set_defaults(flags); - return 1; - } - - if (fstat(fd, &st)) { err = 2; goto out1; } - if (!st.st_size) { - evdns_resolv_set_defaults(flags); - err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0; - goto out1; - } - if (st.st_size > 65535) { err = 3; goto out1; } /* no resolv.conf should be any bigger */ - - resolv = (u8 *) malloc((size_t)st.st_size + 1); - if (!resolv) { err = 4; goto out1; } - - n = 0; - while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) { - n += r; - if (n == st.st_size) - break; - assert(n < st.st_size); - } - if (r < 0) { err = 5; goto out2; } - resolv[n] = 0; /* we malloced an extra byte; this should be fine. */ - - start = (char *) resolv; - for (;;) { - char *const newline = strchr(start, '\n'); - if (!newline) { - resolv_conf_parse_line(start, flags); - break; - } else { - *newline = 0; - resolv_conf_parse_line(start, flags); - start = newline + 1; - } - } - - if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) { - /* no nameservers were configured. */ - evdns_nameserver_ip_add("127.0.0.1"); - err = 6; - } - if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) { - search_set_from_hostname(); - } - -out2: - free(resolv); -out1: - close(fd); - return err; -} - -#ifdef WIN32 -/* Add multiple nameservers from a space-or-comma-separated list. */ -static int -evdns_nameserver_ip_add_line(const char *ips) { - const char *addr; - char *buf; - int r; - while (*ips) { - while (ISSPACE(*ips) || *ips == ',' || *ips == '\t') - ++ips; - addr = ips; - while (ISDIGIT(*ips) || *ips == '.' || *ips == ':') - ++ips; - buf = malloc(ips-addr+1); - if (!buf) return 4; - memcpy(buf, addr, ips-addr); - buf[ips-addr] = '\0'; - r = evdns_nameserver_ip_add(buf); - free(buf); - if (r) return r; - } - return 0; -} - -typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*); - -/* Use the windows GetNetworkParams interface in iphlpapi.dll to */ -/* figure out what our nameservers are. */ -static int -load_nameservers_with_getnetworkparams(void) -{ - /* Based on MSDN examples and inspection of c-ares code. */ - FIXED_INFO *fixed; - HMODULE handle = 0; - ULONG size = sizeof(FIXED_INFO); - void *buf = NULL; - int status = 0, r, added_any; - IP_ADDR_STRING *ns; - GetNetworkParams_fn_t fn; - - if (!(handle = LoadLibrary("iphlpapi.dll"))) { - log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); - status = -1; - goto done; - } - if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) { - log(EVDNS_LOG_WARN, "Could not get address of function."); - status = -1; - goto done; - } - - buf = malloc(size); - if (!buf) { status = 4; goto done; } - fixed = buf; - r = fn(fixed, &size); - if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) { - status = -1; - goto done; - } - if (r != ERROR_SUCCESS) { - free(buf); - buf = malloc(size); - if (!buf) { status = 4; goto done; } - fixed = buf; - r = fn(fixed, &size); - if (r != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG, "fn() failed."); - status = -1; - goto done; - } - } - - assert(fixed); - added_any = 0; - ns = &(fixed->DnsServerList); - while (ns) { - r = evdns_nameserver_ip_add_line(ns->IpAddress.String); - if (r) { - log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d", - (ns->IpAddress.String),(int)GetLastError()); - status = r; - goto done; - } else { - log(EVDNS_LOG_DEBUG,"Succesfully added %s as nameserver",ns->IpAddress.String); - } - - added_any++; - ns = ns->Next; - } - - if (!added_any) { - log(EVDNS_LOG_DEBUG, "No nameservers added."); - status = -1; - } - - done: - if (buf) - free(buf); - if (handle) - FreeLibrary(handle); - return status; -} - -static int -config_nameserver_from_reg_key(HKEY key, const char *subkey) -{ - char *buf; - DWORD bufsz = 0, type = 0; - int status = 0; - - if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz) - != ERROR_MORE_DATA) - return -1; - if (!(buf = malloc(bufsz))) - return -1; - - if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz) - == ERROR_SUCCESS && bufsz > 1) { - status = evdns_nameserver_ip_add_line(buf); - } - - free(buf); - return status; -} - -#define SERVICES_KEY "System\\CurrentControlSet\\Services\\" -#define WIN_NS_9X_KEY SERVICES_KEY "VxD\\MSTCP" -#define WIN_NS_NT_KEY SERVICES_KEY "Tcpip\\Parameters" - -static int -load_nameservers_from_registry(void) -{ - int found = 0; - int r; -#define TRY(k, name) \ - if (!found && config_nameserver_from_reg_key(k,name) == 0) { \ - log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \ - found = 1; \ - } else if (!found) { \ - log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \ - #k,#name); \ - } - - if (((int)GetVersion()) > 0) { /* NT */ - HKEY nt_key = 0, interfaces_key = 0; - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, - KEY_READ, &nt_key) != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); - return -1; - } - r = RegOpenKeyEx(nt_key, "Interfaces", 0, - KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, - &interfaces_key); - if (r != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError()); - return -1; - } - TRY(nt_key, "NameServer"); - TRY(nt_key, "DhcpNameServer"); - TRY(interfaces_key, "NameServer"); - TRY(interfaces_key, "DhcpNameServer"); - RegCloseKey(interfaces_key); - RegCloseKey(nt_key); - } else { - HKEY win_key = 0; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0, - KEY_READ, &win_key) != ERROR_SUCCESS) { - log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError()); - return -1; - } - TRY(win_key, "NameServer"); - RegCloseKey(win_key); - } - - if (found == 0) { - log(EVDNS_LOG_WARN,"Didn't find any nameservers."); - } - - return found ? 0 : -1; -#undef TRY -} - -static int -evdns_config_windows_nameservers(void) -{ - if (load_nameservers_with_getnetworkparams() == 0) - return 0; - return load_nameservers_from_registry(); -} -#endif - -int -evdns_init(void) -{ - int res = 0; -#ifdef WIN32 - res = evdns_config_windows_nameservers(); -#else - res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); -#endif - - return (res); -} - -const char * -evdns_err_to_string(int err) -{ - switch (err) { - case DNS_ERR_NONE: return "no error"; - case DNS_ERR_FORMAT: return "misformatted query"; - case DNS_ERR_SERVERFAILED: return "server failed"; - case DNS_ERR_NOTEXIST: return "name does not exist"; - case DNS_ERR_NOTIMPL: return "query not implemented"; - case DNS_ERR_REFUSED: return "refused"; - - case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed"; - case DNS_ERR_UNKNOWN: return "unknown"; - case DNS_ERR_TIMEOUT: return "request timed out"; - case DNS_ERR_SHUTDOWN: return "dns subsystem shut down"; - default: return "[Unknown error code]"; - } -} - -void -evdns_shutdown(int fail_requests) -{ - struct nameserver *server, *server_next; - struct search_domain *dom, *dom_next; - - while (req_head) { - if (fail_requests) - reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL); - request_finished(req_head, &req_head); - } - while (req_waiting_head) { - if (fail_requests) - reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL); - request_finished(req_waiting_head, &req_waiting_head); - } - global_requests_inflight = global_requests_waiting = 0; - - for (server = server_head; server; server = server_next) { - server_next = server->next; - if (server->socket >= 0) - CLOSE_SOCKET(server->socket); - (void) event_del(&server->event); - if (server->state == 0) - (void) event_del(&server->timeout_event); - free(server); - if (server_next == server_head) - break; - } - server_head = NULL; - global_good_nameservers = 0; - - if (global_search_state) { - for (dom = global_search_state->head; dom; dom = dom_next) { - dom_next = dom->next; - free(dom); - } - free(global_search_state); - global_search_state = NULL; - } - evdns_log_fn = NULL; -} - -#ifdef EVDNS_MAIN -void -main_callback(int result, char type, int count, int ttl, - void *addrs, void *orig) { - char *n = (char*)orig; - int i; - for (i = 0; i < count; ++i) { - if (type == DNS_IPv4_A) { - printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i])); - } else if (type == DNS_PTR) { - printf("%s: %s\n", n, ((char**)addrs)[i]); - } - } - if (!count) { - printf("%s: No answer (%d)\n", n, result); - } - fflush(stdout); -} -void -evdns_server_callback(struct evdns_server_request *req, void *data) -{ - int i, r; - (void)data; - /* dummy; give 192.168.11.11 as an answer for all A questions, - * give foo.bar.example.com as an answer for all PTR questions. */ - for (i = 0; i < req->nquestions; ++i) { - u32 ans = htonl(0xc0a80b0bUL); - if (req->questions[i]->type == EVDNS_TYPE_A && - req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { - printf(" -- replying for %s (A)\n", req->questions[i]->name); - r = evdns_server_request_add_a_reply(req, req->questions[i]->name, - 1, &ans, 10); - if (r<0) - printf("eeep, didn't work.\n"); - } else if (req->questions[i]->type == EVDNS_TYPE_PTR && - req->questions[i]->dns_question_class == EVDNS_CLASS_INET) { - printf(" -- replying for %s (PTR)\n", req->questions[i]->name); - r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name, - "foo.bar.example.com", 10); - } else { - printf(" -- skipping %s [%d %d]\n", req->questions[i]->name, - req->questions[i]->type, req->questions[i]->dns_question_class); - } - } - - r = evdns_request_respond(req, 0); - if (r<0) - printf("eeek, couldn't send reply.\n"); -} - -void -logfn(int is_warn, const char *msg) { - (void) is_warn; - fprintf(stderr, "%s\n", msg); -} -int -main(int c, char **v) { - int idx; - int reverse = 0, verbose = 1, servertest = 0; - if (c<2) { - fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]); - fprintf(stderr, "syntax: %s [-servertest]\n", v[0]); - return 1; - } - idx = 1; - while (idx < c && v[idx][0] == '-') { - if (!strcmp(v[idx], "-x")) - reverse = 1; - else if (!strcmp(v[idx], "-v")) - verbose = 1; - else if (!strcmp(v[idx], "-servertest")) - servertest = 1; - else - fprintf(stderr, "Unknown option %s\n", v[idx]); - ++idx; - } - event_init(); - if (verbose) - evdns_set_log_fn(logfn); - evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf"); - if (servertest) { - int sock; - struct sockaddr_in my_addr; - sock = socket(PF_INET, SOCK_DGRAM, 0); - evutil_make_socket_nonblocking(sock); - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons(10053); - my_addr.sin_addr.s_addr = INADDR_ANY; - if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) { - perror("bind"); - exit(1); - } - evdns_add_server_port(sock, 0, evdns_server_callback, NULL); - } - for (; idx < c; ++idx) { - if (reverse) { - struct in_addr addr; - if (!inet_aton(v[idx], &addr)) { - fprintf(stderr, "Skipping non-IP %s\n", v[idx]); - continue; - } - fprintf(stderr, "resolving %s...\n",v[idx]); - evdns_resolve_reverse(&addr, 0, main_callback, v[idx]); - } else { - fprintf(stderr, "resolving (fwd) %s...\n",v[idx]); - evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]); - } - } - fflush(stdout); - event_dispatch(); - return 0; -} -#endif diff --git a/extra/libevent/evdns.h b/extra/libevent/evdns.h deleted file mode 100644 index 0ad22712962..00000000000 --- a/extra/libevent/evdns.h +++ /dev/null @@ -1,528 +0,0 @@ -/* - * 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() on UNIX and - evdns_config_windows_nameservers() on Windows. - - @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(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(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), evdns_config_windows_nameservers() - */ -int evdns_resolv_conf_parse(int flags, const char *const filename); - - -/** - Obtain nameserver information using the Windows API. - - Attempt to configure a set of nameservers based on platform settings on - a win32 host. Preferentially tries to use GetNetworkParams; if that fails, - looks in the registry. - - @return 0 if successful, or -1 if an error occurred - @see evdns_resolv_conf_parse() - */ -#ifdef MS_WINDOWS -int evdns_config_windows_nameservers(void); -#endif - - -/** - Clear the list of search domains. - */ -void evdns_search_clear(void); - - -/** - Add a domain to the list of search domains - - @param domain the domain to be added to the search list - */ -void evdns_search_add(const char *domain); - - -/** - Set the 'ndots' parameter for searches. - - Sets the number of dots which, when found in a name, causes - the first query to be without any search domain. - - @param ndots the new ndots parameter - */ -void evdns_search_ndots_set(const int ndots); - -/** - A callback that is invoked when a log message is generated - - @param is_warning indicates if the log message is a 'warning' - @param msg the content of the log message - */ -typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg); - - -/** - Set the callback function to handle log messages. - - @param fn the callback to be invoked when a log message is generated - */ -void evdns_set_log_fn(evdns_debug_log_fn_type fn); - -/** - Set a callback that will be invoked to generate transaction IDs. By - default, we pick transaction IDs based on the current clock time. - - @param fn the new callback, or NULL to use the default. - */ -void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void)); - -#define DNS_NO_SEARCH 1 - -/* - * Structures and functions used to implement a DNS server. - */ - -struct evdns_server_request { - int flags; - int nquestions; - struct evdns_server_question **questions; -}; -struct evdns_server_question { - int type; -#ifdef __cplusplus - int dns_question_class; -#else - /* You should refer to this field as "dns_question_class". The - * name "class" works in C for backward compatibility, and will be - * removed in a future version. (1.5 or later). */ - int class; -#define dns_question_class class -#endif - char name[1]; -}; -typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *); -#define EVDNS_ANSWER_SECTION 0 -#define EVDNS_AUTHORITY_SECTION 1 -#define EVDNS_ADDITIONAL_SECTION 2 - -#define EVDNS_TYPE_A 1 -#define EVDNS_TYPE_NS 2 -#define EVDNS_TYPE_CNAME 5 -#define EVDNS_TYPE_SOA 6 -#define EVDNS_TYPE_PTR 12 -#define EVDNS_TYPE_MX 15 -#define EVDNS_TYPE_TXT 16 -#define EVDNS_TYPE_AAAA 28 - -#define EVDNS_QTYPE_AXFR 252 -#define EVDNS_QTYPE_ALL 255 - -#define EVDNS_CLASS_INET 1 - -struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data); -void evdns_close_server_port(struct evdns_server_port *port); - -int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data); -int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); -int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl); -int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl); -int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl); - -int evdns_server_request_respond(struct evdns_server_request *req, int err); -int evdns_server_request_drop(struct evdns_server_request *req); -struct sockaddr; -int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len); - -#ifdef __cplusplus -} -#endif - -#endif /* !EVENTDNS_H */ diff --git a/extra/libevent/event-internal.h b/extra/libevent/event-internal.h deleted file mode 100644 index 59a089ddec4..00000000000 --- a/extra/libevent/event-internal.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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; -}; - -/* Internal use only: Functions that might be missing from <sys/queue.h> */ -/* These following macros are copied from BSD sys/queue.h - Copyright (c) 1991, 1993, The Regents of the University of California. - All rights reserved. -*/ -#ifndef TAILQ_EMPTY -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) NULL -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#endif /* TAILQ_EMPTY */ -#ifndef HAVE_TAILQFOREACH -#define TAILQ_FOREACH(var, head, field) \ - for((var) = TAILQ_FIRST(head); \ - (var) != TAILQ_END(head); \ - (var) = TAILQ_NEXT(var, field)) -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) -#endif /* TAILQ_FOREACH */ - -int _evsignal_set_handler(struct event_base *base, int evsignal, - void (*fn)(int)); -int _evsignal_restore_handler(struct event_base *base, int evsignal); - -#ifdef __cplusplus -} -#endif - -#endif /* _EVENT_INTERNAL_H_ */ diff --git a/extra/libevent/event.c b/extra/libevent/event.c deleted file mode 100644 index 07498c709c8..00000000000 --- a/extra/libevent/event.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * 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. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -#include "misc.h" -#endif -#include <sys/types.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <sys/_time.h> -#endif -#include <sys/queue.h> -#include <stdio.h> -#include <stdlib.h> -#ifndef WIN32 -#include <unistd.h> -#endif -#include <errno.h> -#include <signal.h> -#include <string.h> -#include <assert.h> -#include <time.h> - -#include "event.h" -#include "event-internal.h" -#include "evutil.h" -#include "log.h" - -#ifdef HAVE_EVENT_PORTS -extern const struct eventop evportops; -#endif -#ifdef HAVE_SELECT -extern const struct eventop selectops; -#endif -#ifdef HAVE_POLL -extern const struct eventop pollops; -#endif -#ifdef HAVE_EPOLL -extern const struct eventop epollops; -#endif -#ifdef HAVE_WORKING_KQUEUE -extern const struct eventop kqops; -#endif -#ifdef HAVE_DEVPOLL -extern const struct eventop devpollops; -#endif -#ifdef WIN32 -extern const struct eventop win32ops; -#endif - -/* In order of preference */ -const struct eventop *eventops[] = { -#ifdef HAVE_EVENT_PORTS - &evportops, -#endif -#ifdef HAVE_WORKING_KQUEUE - &kqops, -#endif -#ifdef HAVE_EPOLL - &epollops, -#endif -#ifdef HAVE_DEVPOLL - &devpollops, -#endif -#ifdef HAVE_POLL - &pollops, -#endif -#ifdef HAVE_SELECT - &selectops, -#endif -#ifdef WIN32 - &win32ops, -#endif - NULL -}; - -/* Global state */ -struct event_base *current_base = NULL; -extern struct event_base *evsignal_base; -static int use_monotonic; - -/* Handle signals - This is a deprecated interface */ -int (*event_sigcb)(void); /* Signal callback when gotsig is set */ -volatile sig_atomic_t event_gotsig; /* Set in signal handler */ - -/* Prototypes */ -static void event_queue_insert(struct event_base *, struct event *, int); -static void event_queue_remove(struct event_base *, struct event *, int); -static int event_haveevents(struct event_base *); - -static void event_process_active(struct event_base *); - -static int timeout_next(struct event_base *, struct timeval **); -static void timeout_process(struct event_base *); -static void timeout_correct(struct event_base *, struct timeval *); - -static void -detect_monotonic(void) -{ -#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - use_monotonic = 1; -#endif -} - -static int -gettime(struct timeval *tp) -{ -#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) - struct timespec ts; - - if (use_monotonic) { - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) - return (-1); - - tp->tv_sec = ts.tv_sec; - tp->tv_usec = ts.tv_nsec / 1000; - return (0); - } -#endif - - return (gettimeofday(tp, NULL)); -} - -struct event_base * -event_init(void) -{ - struct event_base *base = event_base_new(); - - if (base != NULL) - current_base = base; - - return (base); -} - -struct event_base * -event_base_new(void) -{ - int i; - struct event_base *base; - - if ((base = calloc(1, sizeof(struct event_base))) == NULL) - event_err(1, "%s: calloc", __func__); - - event_sigcb = NULL; - event_gotsig = 0; - - detect_monotonic(); - gettime(&base->event_tv); - - min_heap_ctor(&base->timeheap); - TAILQ_INIT(&base->eventqueue); - TAILQ_INIT(&base->sig.signalqueue); - base->sig.ev_signal_pair[0] = -1; - base->sig.ev_signal_pair[1] = -1; - - base->evbase = NULL; - for (i = 0; eventops[i] && !base->evbase; i++) { - base->evsel = eventops[i]; - - base->evbase = base->evsel->init(base); - } - - if (base->evbase == NULL) - event_errx(1, "%s: no event mechanism available", __func__); - - if (getenv("EVENT_SHOW_METHOD")) - event_msgx("libevent using: %s\n", - base->evsel->name); - - /* allocate a single active event queue */ - event_base_priority_init(base, 1); - - return (base); -} - -void -event_base_free(struct event_base *base) -{ - int i, n_deleted=0; - struct event *ev; - - if (base == NULL && current_base) - base = current_base; - if (base == current_base) - current_base = NULL; - - /* XXX(niels) - check for internal events first */ - assert(base); - /* Delete all non-internal events. */ - for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) { - struct event *next = TAILQ_NEXT(ev, ev_next); - if (!(ev->ev_flags & EVLIST_INTERNAL)) { - event_del(ev); - ++n_deleted; - } - ev = next; - } - while ((ev = min_heap_top(&base->timeheap)) != NULL) { - event_del(ev); - ++n_deleted; - } - - if (n_deleted) - event_debug(("%s: %d events were still set in base", - __func__, n_deleted)); - - if (base->evsel->dealloc != NULL) - base->evsel->dealloc(base, base->evbase); - - for (i = 0; i < base->nactivequeues; ++i) - assert(TAILQ_EMPTY(base->activequeues[i])); - - assert(min_heap_empty(&base->timeheap)); - min_heap_dtor(&base->timeheap); - - for (i = 0; i < base->nactivequeues; ++i) - free(base->activequeues[i]); - free(base->activequeues); - - assert(TAILQ_EMPTY(&base->eventqueue)); - - free(base); -} - -/* reinitialized the event base after a fork */ -int -event_reinit(struct event_base *base) -{ - const struct eventop *evsel = base->evsel; - void *evbase = base->evbase; - int res = 0; - struct event *ev; - - /* check if this event mechanism requires reinit */ - if (!evsel->need_reinit) - return (0); - - if (base->evsel->dealloc != NULL) - base->evsel->dealloc(base, base->evbase); - base->evbase = evsel->init(base); - if (base->evbase == NULL) - event_errx(1, "%s: could not reinitialize event mechanism", - __func__); - - TAILQ_FOREACH(ev, &base->eventqueue, ev_next) { - if (evsel->add(evbase, ev) == -1) - res = -1; - } - - return (res); -} - -int -event_priority_init(int npriorities) -{ - return event_base_priority_init(current_base, npriorities); -} - -int -event_base_priority_init(struct event_base *base, int npriorities) -{ - int i; - - if (base->event_count_active) - return (-1); - - if (base->nactivequeues && npriorities != base->nactivequeues) { - for (i = 0; i < base->nactivequeues; ++i) { - free(base->activequeues[i]); - } - free(base->activequeues); - } - - /* Allocate our priority queues */ - base->nactivequeues = npriorities; - base->activequeues = (struct event_list **)calloc(base->nactivequeues, - npriorities * sizeof(struct event_list *)); - if (base->activequeues == NULL) - event_err(1, "%s: calloc", __func__); - - for (i = 0; i < base->nactivequeues; ++i) { - base->activequeues[i] = malloc(sizeof(struct event_list)); - if (base->activequeues[i] == NULL) - event_err(1, "%s: malloc", __func__); - TAILQ_INIT(base->activequeues[i]); - } - - return (0); -} - -int -event_haveevents(struct event_base *base) -{ - return (base->event_count > 0); -} - -/* - * Active events are stored in priority queues. Lower priorities are always - * process before higher priorities. Low priority events can starve high - * priority ones. - */ - -static void -event_process_active(struct event_base *base) -{ - struct event *ev; - struct event_list *activeq = NULL; - int i; - short ncalls; - - for (i = 0; i < base->nactivequeues; ++i) { - if (TAILQ_FIRST(base->activequeues[i]) != NULL) { - activeq = base->activequeues[i]; - break; - } - } - - assert(activeq != NULL); - - for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) { - if (ev->ev_events & EV_PERSIST) - event_queue_remove(base, ev, EVLIST_ACTIVE); - else - event_del(ev); - - /* Allows deletes to work */ - ncalls = ev->ev_ncalls; - ev->ev_pncalls = &ncalls; - while (ncalls) { - ncalls--; - ev->ev_ncalls = ncalls; - (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg); - if (event_gotsig || base->event_break) - return; - } - } -} - -/* - * Wait continously for events. We exit only if no events are left. - */ - -int -event_dispatch(void) -{ - return (event_loop(0)); -} - -int -event_base_dispatch(struct event_base *event_base) -{ - return (event_base_loop(event_base, 0)); -} - -const char * -event_base_get_method(struct event_base *base) -{ - assert(base); - return (base->evsel->name); -} - -static void -event_loopexit_cb(int fd __attribute__((unused)), - short what __attribute__((unused)), void *arg) -{ - struct event_base *base = arg; - base->event_gotterm = 1; -} - -/* not thread safe */ -int -event_loopexit(struct timeval *tv) -{ - return (event_once(-1, EV_TIMEOUT, &event_loopexit_cb, - current_base, tv)); -} - -int -event_base_loopexit(struct event_base *event_base, struct timeval *tv) -{ - return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb, - event_base, tv)); -} - -/* not thread safe */ -int -event_loopbreak(void) -{ - return (event_base_loopbreak(current_base)); -} - -int -event_base_loopbreak(struct event_base *event_base) -{ - if (event_base == NULL) - return (-1); - - event_base->event_break = 1; - return (0); -} - - - -/* not thread safe */ - -int -event_loop(int flags) -{ - return event_base_loop(current_base, flags); -} - -int -event_base_loop(struct event_base *base, int flags) -{ - const struct eventop *evsel = base->evsel; - void *evbase = base->evbase; - struct timeval tv; - struct timeval *tv_p; - int res, done; - - if(!TAILQ_EMPTY(&base->sig.signalqueue)) - evsignal_base = base; - done = 0; - while (!done) { - /* Terminate the loop if we have been asked to */ - if (base->event_gotterm) { - base->event_gotterm = 0; - break; - } - - if (base->event_break) { - base->event_break = 0; - break; - } - - /* You cannot use this interface for multi-threaded apps */ - while (event_gotsig) { - event_gotsig = 0; - if (event_sigcb) { - res = (*event_sigcb)(); - if (res == -1) { - errno = EINTR; - return (-1); - } - } - } - - timeout_correct(base, &tv); - - tv_p = &tv; - if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) { - timeout_next(base, &tv_p); - } else { - /* - * if we have active events, we just poll new events - * without waiting. - */ - evutil_timerclear(&tv); - } - - /* If we have no events, we just exit */ - if (!event_haveevents(base)) { - event_debug(("%s: no events registered.", __func__)); - return (1); - } - - res = evsel->dispatch(base, evbase, tv_p); - - if (res == -1) - return (-1); - - timeout_process(base); - - if (base->event_count_active) { - event_process_active(base); - if (!base->event_count_active && (flags & EVLOOP_ONCE)) - done = 1; - } else if (flags & EVLOOP_NONBLOCK) - done = 1; - } - - event_debug(("%s: asked to terminate loop.", __func__)); - return (0); -} - -/* Sets up an event for processing once */ - -struct event_once { - struct event ev; - - void (*cb)(int, short, void *); - void *arg; -}; - -/* One-time callback, it deletes itself */ - -static void -event_once_cb(int fd, short events, void *arg) -{ - struct event_once *eonce = arg; - - (*eonce->cb)(fd, events, eonce->arg); - free(eonce); -} - -/* not threadsafe, event scheduled once. */ -int -event_once(int fd, short events, - void (*callback)(int, short, void *), void *arg, struct timeval *tv) -{ - return event_base_once(current_base, fd, events, callback, arg, tv); -} - -/* Schedules an event once */ -int -event_base_once(struct event_base *base, int fd, short events, - void (*callback)(int, short, void *), void *arg, struct timeval *tv) -{ - struct event_once *eonce; - struct timeval etv; - int res; - - /* We cannot support signals that just fire once */ - if (events & EV_SIGNAL) - return (-1); - - if ((eonce = calloc(1, sizeof(struct event_once))) == NULL) - return (-1); - - eonce->cb = callback; - eonce->arg = arg; - - if (events == EV_TIMEOUT) { - if (tv == NULL) { - evutil_timerclear(&etv); - tv = &etv; - } - - evtimer_set(&eonce->ev, event_once_cb, eonce); - } else if (events & (EV_READ|EV_WRITE)) { - events &= EV_READ|EV_WRITE; - - event_set(&eonce->ev, fd, events, event_once_cb, eonce); - } else { - /* Bad event combination */ - free(eonce); - return (-1); - } - - res = event_base_set(base, &eonce->ev); - if (res == 0) - res = event_add(&eonce->ev, tv); - if (res != 0) { - free(eonce); - return (res); - } - - return (0); -} - -void -event_set(struct event *ev, int fd, short events, - void (*callback)(int, short, void *), void *arg) -{ - /* Take the current base - caller needs to set the real base later */ - ev->ev_base = current_base; - - ev->ev_callback = callback; - ev->ev_arg = arg; - ev->ev_fd = fd; - ev->ev_events = events; - ev->ev_res = 0; - ev->ev_flags = EVLIST_INIT; - ev->ev_ncalls = 0; - ev->ev_pncalls = NULL; - - min_heap_elem_init(ev); - - /* by default, we put new events into the middle priority */ - if(current_base) - ev->ev_pri = current_base->nactivequeues/2; -} - -int -event_base_set(struct event_base *base, struct event *ev) -{ - /* Only innocent events may be assigned to a different base */ - if (ev->ev_flags != EVLIST_INIT) - return (-1); - - ev->ev_base = base; - ev->ev_pri = base->nactivequeues/2; - - return (0); -} - -/* - * Set's the priority of an event - if an event is already scheduled - * changing the priority is going to fail. - */ - -int -event_priority_set(struct event *ev, int pri) -{ - if (ev->ev_flags & EVLIST_ACTIVE) - return (-1); - if (pri < 0 || pri >= ev->ev_base->nactivequeues) - return (-1); - - ev->ev_pri = pri; - - return (0); -} - -/* - * Checks if a specific event is pending or scheduled. - */ - -int -event_pending(struct event *ev, short event, struct timeval *tv) -{ - struct timeval now, res; - int flags = 0; - - if (ev->ev_flags & EVLIST_INSERTED) - flags |= (ev->ev_events & (EV_READ|EV_WRITE)); - if (ev->ev_flags & EVLIST_ACTIVE) - flags |= ev->ev_res; - if (ev->ev_flags & EVLIST_TIMEOUT) - flags |= EV_TIMEOUT; - if (ev->ev_flags & EVLIST_SIGNAL) - flags |= EV_SIGNAL; - - event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL); - - /* See if there is a timeout that we should report */ - if (tv != NULL && (flags & event & EV_TIMEOUT)) { - gettime(&now); - evutil_timersub(&ev->ev_timeout, &now, &res); - /* correctly remap to real time */ - gettimeofday(&now, NULL); - evutil_timeradd(&now, &res, tv); - } - - return (flags & event); -} - -int -event_add(struct event *ev, struct timeval *tv) -{ - struct event_base *base = ev->ev_base; - const struct eventop *evsel = base->evsel; - void *evbase = base->evbase; - - event_debug(( - "event_add: event: %p, %s%s%scall %p", - ev, - ev->ev_events & EV_READ ? "EV_READ " : " ", - ev->ev_events & EV_WRITE ? "EV_WRITE " : " ", - tv ? "EV_TIMEOUT " : " ", - ev->ev_callback)); - - assert(!(ev->ev_flags & ~EVLIST_ALL)); - - if (tv != NULL) { - struct timeval now; - - if (ev->ev_flags & EVLIST_TIMEOUT) - event_queue_remove(base, ev, EVLIST_TIMEOUT); - else if (min_heap_reserve(&base->timeheap, - 1 + min_heap_size(&base->timeheap)) == -1) - return (-1); /* ENOMEM == errno */ - - /* Check if it is active due to a timeout. Rescheduling - * this timeout before the callback can be executed - * removes it from the active list. */ - if ((ev->ev_flags & EVLIST_ACTIVE) && - (ev->ev_res & EV_TIMEOUT)) { - /* See if we are just active executing this - * event in a loop - */ - if (ev->ev_ncalls && ev->ev_pncalls) { - /* Abort loop */ - *ev->ev_pncalls = 0; - } - - event_queue_remove(base, ev, EVLIST_ACTIVE); - } - - gettime(&now); - evutil_timeradd(&now, tv, &ev->ev_timeout); - - event_debug(( - "event_add: timeout in %d seconds, call %p", - tv->tv_sec, ev->ev_callback)); - - event_queue_insert(base, ev, EVLIST_TIMEOUT); - } - - if ((ev->ev_events & (EV_READ|EV_WRITE)) && - !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) { - int res = evsel->add(evbase, ev); - if (res != -1) - event_queue_insert(base, ev, EVLIST_INSERTED); - - return (res); - } else if ((ev->ev_events & EV_SIGNAL) && - !(ev->ev_flags & EVLIST_SIGNAL)) { - int res = evsel->add(evbase, ev); - if (res != -1) - event_queue_insert(base, ev, EVLIST_SIGNAL); - - return (res); - } - - return (0); -} - -int -event_del(struct event *ev) -{ - struct event_base *base; - const struct eventop *evsel; - void *evbase; - - event_debug(("event_del: %p, callback %p", - ev, ev->ev_callback)); - - /* An event without a base has not been added */ - if (ev->ev_base == NULL) - return (-1); - - base = ev->ev_base; - evsel = base->evsel; - evbase = base->evbase; - - assert(!(ev->ev_flags & ~EVLIST_ALL)); - - /* See if we are just active executing this event in a loop */ - if (ev->ev_ncalls && ev->ev_pncalls) { - /* Abort loop */ - *ev->ev_pncalls = 0; - } - - if (ev->ev_flags & EVLIST_TIMEOUT) - event_queue_remove(base, ev, EVLIST_TIMEOUT); - - if (ev->ev_flags & EVLIST_ACTIVE) - event_queue_remove(base, ev, EVLIST_ACTIVE); - - if (ev->ev_flags & EVLIST_INSERTED) { - event_queue_remove(base, ev, EVLIST_INSERTED); - return (evsel->del(evbase, ev)); - } else if (ev->ev_flags & EVLIST_SIGNAL) { - event_queue_remove(base, ev, EVLIST_SIGNAL); - return (evsel->del(evbase, ev)); - } - - return (0); -} - -void -event_active(struct event *ev, int res, short ncalls) -{ - /* We get different kinds of events, add them together */ - if (ev->ev_flags & EVLIST_ACTIVE) { - ev->ev_res |= res; - return; - } - - ev->ev_res = res; - ev->ev_ncalls = ncalls; - ev->ev_pncalls = NULL; - event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE); -} - -static int -timeout_next(struct event_base *base, struct timeval **tv_p) -{ - struct timeval now; - struct event *ev; - struct timeval *tv = *tv_p; - - if ((ev = min_heap_top(&base->timeheap)) == NULL) { - /* if no time-based events are active wait for I/O */ - *tv_p = NULL; - return (0); - } - - if (gettime(&now) == -1) - return (-1); - - if (evutil_timercmp(&ev->ev_timeout, &now, <=)) { - evutil_timerclear(tv); - return (0); - } - - evutil_timersub(&ev->ev_timeout, &now, tv); - - assert(tv->tv_sec >= 0); - assert(tv->tv_usec >= 0); - - event_debug(("timeout_next: in %d seconds", tv->tv_sec)); - return (0); -} - -/* - * Determines if the time is running backwards by comparing the current - * time against the last time we checked. Not needed when using clock - * monotonic. - */ - -static void -timeout_correct(struct event_base *base, struct timeval *tv) -{ - struct event **pev; - unsigned int size; - struct timeval off; - - if (use_monotonic) - return; - - /* Check if time is running backwards */ - gettime(tv); - if (evutil_timercmp(tv, &base->event_tv, >=)) { - base->event_tv = *tv; - return; - } - - event_debug(("%s: time is running backwards, corrected", - __func__)); - evutil_timersub(&base->event_tv, tv, &off); - - /* - * We can modify the key element of the node without destroying - * the key, beause we apply it to all in the right order. - */ - pev = base->timeheap.p; - size = base->timeheap.n; - for (; size-- > 0; ++pev) { - struct timeval *ev_tv = &(**pev).ev_timeout; - evutil_timersub(ev_tv, &off, ev_tv); - } -} - -void -timeout_process(struct event_base *base) -{ - struct timeval now; - struct event *ev; - - if (min_heap_empty(&base->timeheap)) - return; - - gettime(&now); - - while ((ev = min_heap_top(&base->timeheap))) { - if (evutil_timercmp(&ev->ev_timeout, &now, >)) - break; - - /* delete this event from the I/O queues */ - event_del(ev); - - event_debug(("timeout_process: call %p", - ev->ev_callback)); - event_active(ev, EV_TIMEOUT, 1); - } -} - -void -event_queue_remove(struct event_base *base, struct event *ev, int queue) -{ - if (!(ev->ev_flags & queue)) - event_errx(1, "%s: %p(fd %d) not on queue %x", __func__, - ev, ev->ev_fd, queue); - - if (~ev->ev_flags & EVLIST_INTERNAL) - base->event_count--; - - ev->ev_flags &= ~queue; - switch (queue) { - case EVLIST_ACTIVE: - base->event_count_active--; - TAILQ_REMOVE(base->activequeues[ev->ev_pri], - ev, ev_active_next); - break; - case EVLIST_SIGNAL: - TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next); - break; - case EVLIST_TIMEOUT: - min_heap_erase(&base->timeheap, ev); - break; - case EVLIST_INSERTED: - TAILQ_REMOVE(&base->eventqueue, ev, ev_next); - break; - default: - event_errx(1, "%s: unknown queue %x", __func__, queue); - } -} - -void -event_queue_insert(struct event_base *base, struct event *ev, int queue) -{ - if (ev->ev_flags & queue) { - /* Double insertion is possible for active events */ - if (queue & EVLIST_ACTIVE) - return; - - event_errx(1, "%s: %p(fd %d) already on queue %x", __func__, - ev, ev->ev_fd, queue); - } - - if (~ev->ev_flags & EVLIST_INTERNAL) - base->event_count++; - - ev->ev_flags |= queue; - switch (queue) { - case EVLIST_ACTIVE: - base->event_count_active++; - TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], - ev,ev_active_next); - break; - case EVLIST_SIGNAL: - TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next); - break; - case EVLIST_TIMEOUT: { - min_heap_push(&base->timeheap, ev); - break; - } - case EVLIST_INSERTED: - TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); - break; - default: - event_errx(1, "%s: unknown queue %x", __func__, queue); - } -} - -/* Functions for debugging */ - -const char * -event_get_version(void) -{ - return (VERSION); -} - -/* - * No thread-safe interface needed - the information should be the same - * for all threads. - */ - -const char * -event_get_method(void) -{ - return (current_base->evsel->name); -} diff --git a/extra/libevent/event.h b/extra/libevent/event.h deleted file mode 100644 index 078c940770e..00000000000 --- a/extra/libevent/event.h +++ /dev/null @@ -1,1129 +0,0 @@ -/* - * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _EVENT_H_ -#define _EVENT_H_ - -/** @mainpage - - @section intro Introduction - - libevent is an event notification library for developing scalable network - servers. The libevent API provides a mechanism to execute a callback - function when a specific event occurs on a file descriptor or after a - timeout has been reached. Furthermore, libevent also support callbacks due - to signals or regular timeouts. - - libevent is meant to replace the event loop found in event driven network - servers. An application just needs to call event_dispatch() and then add or - remove events dynamically without having to change the event loop. - - Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and - epoll(4). It also has experimental support for real-time signals. The - internal event mechanism is completely independent of the exposed event API, - and a simple update of libevent can provide new functionality without having - to redesign the applications. As a result, Libevent allows for portable - application development and provides the most scalable event notification - mechanism available on an operating system. Libevent can also be used for - multi-threaded aplications; see Steven Grimm's explanation. Libevent should - compile on Linux, *BSD, Mac OS X, Solaris and Windows. - - @section usage Standard usage - - Every program that uses libevent must include the <event.h> header, and pass - the -levent flag to the linker. Before using any of the functions in the - library, you must call event_init() or event_base_new() to perform one-time - initialization of the libevent library. - - @section event Event notification - - For each file descriptor that you wish to monitor, you must declare an event - structure and call event_set() to initialize the members of the structure. - To enable notification, you add the structure to the list of monitored - events by calling event_add(). The event structure must remain allocated as - long as it is active, so it should be allocated on the heap. Finally, you - call event_dispatch() to loop and dispatch events. - - @section bufferevent I/O Buffers - - libevent provides an abstraction on top of the regular event callbacks. This - abstraction is called a buffered event. A buffered event provides input and - output buffers that get filled and drained automatically. The user of a - buffered event no longer deals directly with the I/O, but instead is reading - from input and writing to output buffers. - - Once initialized via bufferevent_new(), the bufferevent structure can be - used repeatedly with bufferevent_enable() and bufferevent_disable(). - Instead of reading and writing directly to a socket, you would call - bufferevent_read() and bufferevent_write(). - - When read enabled the bufferevent will try to read from the file descriptor - and call the read callback. The write callback is executed whenever the - output buffer is drained below the write low watermark, which is 0 by - default. - - @section timers Timers - - libevent can also be used to create timers that invoke a callback after a - certain amount of time has expired. The evtimer_set() function prepares an - event struct to be used as a timer. To activate the timer, call - evtimer_add(). Timers can be deactivated by calling evtimer_del(). - - @section timeouts Timeouts - - In addition to simple timers, libevent can assign timeout events to file - descriptors that are triggered whenever a certain amount of time has passed - with no activity on a file descriptor. The timeout_set() function - initializes an event struct for use as a timeout. Once initialized, the - event must be activated by using timeout_add(). To cancel the timeout, call - timeout_del(). - - @section evdns Asynchronous DNS resolution - - libevent provides an asynchronous DNS resolver that should be used instead - of the standard DNS resolver functions. These functions can be imported by - including the <evdns.h> header in your program. Before using any of the - resolver functions, you must call evdns_init() to initialize the library. To - convert a hostname to an IP address, you call the evdns_resolve_ipv4() - function. To perform a reverse lookup, you would call the - evdns_resolve_reverse() function. All of these functions use callbacks to - avoid blocking while the lookup is performed. - - @section evhttp Event-driven HTTP servers - - libevent provides a very simple event-driven HTTP server that can be - embedded in your program and used to service HTTP requests. - - To use this capability, you need to include the <evhttp.h> header in your - program. You create the server by calling evhttp_new(). Add addresses and - ports to listen on with evhttp_bind_socket(). You then register one or more - callbacks to handle incoming requests. Each URI can be assigned a callback - via the evhttp_set_cb() function. A generic callback function can also be - registered via evhttp_set_gencb(); this callback will be invoked if no other - callbacks have been registered for a given URI. - - @section evrpc A framework for RPC servers and clients - - libevents provides a framework for creating RPC servers and clients. It - takes care of marshaling and unmarshaling all data structures. - - @section api API Reference - - To browse the complete documentation of the libevent API, click on any of - the following links. - - event.h - The primary libevent header - - evdns.h - Asynchronous DNS resolution - - evhttp.h - An embedded libevent-based HTTP server - - evrpc.h - A framework for creating RPC servers and clients - - */ - -/** @file event.h - - A library for writing event-driven network servers - - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <my_attribute.h> - -#include <event-config.h> -#ifdef _EVENT_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef _EVENT_HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef _EVENT_HAVE_STDINT_H -#include <stdint.h> -#endif -#include <stdarg.h> - -/* For int types. */ -#include <evutil.h> - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -typedef unsigned char u_char; -typedef unsigned short u_short; -#endif - -#define EVLIST_TIMEOUT 0x01 -#define EVLIST_INSERTED 0x02 -#define EVLIST_SIGNAL 0x04 -#define EVLIST_ACTIVE 0x08 -#define EVLIST_INTERNAL 0x10 -#define EVLIST_INIT 0x80 - -/* EVLIST_X_ Private space: 0x1000-0xf000 */ -#define EVLIST_ALL (0xf000 | 0x9f) - -#define EV_TIMEOUT 0x01 -#define EV_READ 0x02 -#define EV_WRITE 0x04 -#define EV_SIGNAL 0x08 -#define EV_PERSIST 0x10 /* Persistant event */ - -/* Fix so that ppl dont have to run with <sys/queue.h> */ -#ifndef TAILQ_ENTRY -#define _EVENT_DEFINED_TQENTRY -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} -#endif /* !TAILQ_ENTRY */ - -struct event_base; -struct event { - TAILQ_ENTRY (event) ev_next; - TAILQ_ENTRY (event) ev_active_next; - TAILQ_ENTRY (event) ev_signal_next; - unsigned int min_heap_idx; /* for managing timeouts */ - - struct event_base *ev_base; - - int ev_fd; - short ev_events; - short ev_ncalls; - short *ev_pncalls; /* Allows deletes in callback */ - - struct timeval ev_timeout; - - int ev_pri; /* smaller numbers are higher priority */ - - void (*ev_callback)(int, short, void *arg); - void *ev_arg; - - int ev_res; /* result passed to event callback */ - int ev_flags; -}; - -#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd -#define EVENT_FD(ev) (int)(ev)->ev_fd - -/* - * Key-Value pairs. Can be used for HTTP headers but also for - * query argument parsing. - */ -struct evkeyval { - TAILQ_ENTRY(evkeyval) next; - - char *key; - char *value; -}; - -#ifdef _EVENT_DEFINED_TQENTRY -#undef TAILQ_ENTRY -struct event_list; -struct evkeyvalq; -#undef _EVENT_DEFINED_TQENTRY -#else -TAILQ_HEAD (event_list, event); -TAILQ_HEAD (evkeyvalq, evkeyval); -#endif /* _EVENT_DEFINED_TQENTRY */ - -/** - Initialize the event API. - - Use event_base_new() to initialize a new event base, but does not set - the current_base global. If using only event_base_new(), each event - added must have an event base set with event_base_set() - - @see event_base_set(), event_base_free(), event_init() - */ -struct event_base *event_base_new(void); - -/** - Initialize the event API. - - The event API needs to be initialized with event_init() before it can be - used. Sets the current_base global representing the default base for - events that have no base associated with them. - - @see event_base_set(), event_base_new() - */ -struct event_base *event_init(void); - -/** - Reinitialized the event base after a fork - - Some event mechanisms do not survive across fork. The event base needs - to be reinitialized with the event_reinit() function. - - @param base the event base that needs to be re-initialized - @return 0 if successful, or -1 if some events could not be re-added. - @see event_base_new(), event_init() -*/ -int event_reinit(struct event_base *base); - -/** - Loop to process events. - - In order to process events, an application needs to call - event_dispatch(). This function only returns on error, and should - replace the event core of the application program. - - @see event_base_dispatch() - */ -int event_dispatch(void); - - -/** - Threadsafe event dispatching loop. - - @param eb the event_base structure returned by event_init() - @see event_init(), event_dispatch() - */ -int event_base_dispatch(struct event_base *); - - -/** - Get the kernel event notification mechanism used by libevent. - - @param eb the event_base structure returned by event_base_new() - @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) - */ -const char *event_base_get_method(struct event_base *); - - -/** - Deallocate all memory associated with an event_base, and free the base. - - Note that this function will not close any fds or free any memory passed - to event_set as the argument to callback. - - @param eb an event_base to be freed - */ -void event_base_free(struct event_base *); - - -#define _EVENT_LOG_DEBUG 0 -#define _EVENT_LOG_MSG 1 -#define _EVENT_LOG_WARN 2 -#define _EVENT_LOG_ERR 3 -typedef void (*event_log_cb)(int severity, const char *msg); -/** - Redirect libevent's log messages. - - @param cb a function taking two arguments: an integer severity between - _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string. If cb is NULL, - then the default log is used. - */ -void event_set_log_callback(event_log_cb cb); - -/** - Associate a different event base with an event. - - @param eb the event base - @param ev the event - */ -int event_base_set(struct event_base *, struct event *); - -/** - event_loop() flags - */ -/*@{*/ -#define EVLOOP_ONCE 0x01 /**< Block at most once. */ -#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */ -/*@}*/ - -/** - Handle events. - - This is a more flexible version of event_dispatch(). - - @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK - @return 0 if successful, -1 if an error occurred, or 1 if no events were - registered. - @see event_loopexit(), event_base_loop() -*/ -int event_loop(int); - -/** - Handle events (threadsafe version). - - This is a more flexible version of event_base_dispatch(). - - @param eb the event_base structure returned by event_init() - @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK - @return 0 if successful, -1 if an error occurred, or 1 if no events were - registered. - @see event_loopexit(), event_base_loop() - */ -int event_base_loop(struct event_base *, int); - -/** - Exit the event loop after the specified time. - - The next event_loop() iteration after the given timer expires will - complete normally (handling all queued events) then exit without - blocking for events again. - - Subsequent invocations of event_loop() will proceed normally. - - @param tv the amount of time after which the loop should terminate. - @return 0 if successful, or -1 if an error occurred - @see event_loop(), event_base_loop(), event_base_loopexit() - */ -int event_loopexit(struct timeval *); - - -/** - Exit the event loop after the specified time (threadsafe variant). - - The next event_base_loop() iteration after the given timer expires will - complete normally (handling all queued events) then exit without - blocking for events again. - - Subsequent invocations of event_base_loop() will proceed normally. - - @param eb the event_base structure returned by event_init() - @param tv the amount of time after which the loop should terminate. - @return 0 if successful, or -1 if an error occurred - @see event_loopexit() - */ -int event_base_loopexit(struct event_base *, struct timeval *); - -/** - Abort the active event_loop() immediately. - - event_loop() will abort the loop after the next event is completed; - event_loopbreak() is typically invoked from this event's callback. - This behavior is analogous to the "break;" statement. - - Subsequent invocations of event_loop() will proceed normally. - - @return 0 if successful, or -1 if an error occurred - @see event_base_loopbreak(), event_loopexit() - */ -int event_loopbreak(void); - -/** - Abort the active event_base_loop() immediately. - - event_base_loop() will abort the loop after the next event is completed; - event_base_loopbreak() is typically invoked from this event's callback. - This behavior is analogous to the "break;" statement. - - Subsequent invocations of event_loop() will proceed normally. - - @param eb the event_base structure returned by event_init() - @return 0 if successful, or -1 if an error occurred - @see event_base_loopexit - */ -int event_base_loopbreak(struct event_base *); - - -/** - Add a timer event. - - @param ev the event struct - @param tv timeval struct - */ -#define evtimer_add(ev, tv) event_add(ev, tv) - - -/** - Define a timer event. - - @param ev event struct to be modified - @param cb callback function - @param arg argument that will be passed to the callback function - */ -#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) - - -/** - * Delete a timer event. - * - * @param ev the event struct to be disabled - */ -#define evtimer_del(ev) event_del(ev) -#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) -#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) - -/** - * Add a timeout event. - * - * @param ev the event struct to be disabled - * @param tv the timeout value, in seconds - */ -#define timeout_add(ev, tv) event_add(ev, tv) - - -/** - * Define a timeout event. - * - * @param ev the event struct to be defined - * @param cb the callback to be invoked when the timeout expires - * @param arg the argument to be passed to the callback - */ -#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg) - - -/** - * Disable a timeout event. - * - * @param ev the timeout event to be disabled - */ -#define timeout_del(ev) event_del(ev) - -#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv) -#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) - -#define signal_add(ev, tv) event_add(ev, tv) -#define signal_set(ev, x, cb, arg) \ - event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg) -#define signal_del(ev) event_del(ev) -#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv) -#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) - -/** - Prepare an event structure to be added. - - The function event_set() prepares the event structure ev to be used in - future calls to event_add() and event_del(). The event will be prepared to - call the function specified by the fn argument with an int argument - indicating the file descriptor, a short argument indicating the type of - event, and a void * argument given in the arg argument. The fd indicates - the file descriptor that should be monitored for events. The events can be - either EV_READ, EV_WRITE, or both. Indicating that an application can read - or write from the file descriptor respectively without blocking. - - The function fn will be called with the file descriptor that triggered the - event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL, - EV_READ, or EV_WRITE. The additional flag EV_PERSIST makes an event_add() - persistent until event_del() has been called. - - @param ev an event struct to be modified - @param fd the file descriptor to be monitored - @param event desired events to monitor; can be EV_READ and/or EV_WRITE - @param fn callback function to be invoked when the event occurs - @param arg an argument to be passed to the callback function - - @see event_add(), event_del(), event_once() - - */ -void event_set(struct event *, int, short, void (*)(int, short, void *), void *); - -/** - Schedule a one-time event to occur. - - The function event_once() is similar to event_set(). However, it schedules - a callback to be called exactly once and does not require the caller to - prepare an event structure. - - @param fd a file descriptor to monitor - @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ | - EV_WRITE - @param callback callback function to be invoked when the event occurs - @param arg an argument to be passed to the callback function - @param timeout the maximum amount of time to wait for the event, or NULL - to wait forever - @return 0 if successful, or -1 if an error occurred - @see event_set() - - */ -int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); - - -/** - Schedule a one-time event (threadsafe variant) - - The function event_base_once() is similar to event_set(). However, it - schedules a callback to be called exactly once and does not require the - caller to prepare an event structure. - - @param base an event_base returned by event_init() - @param fd a file descriptor to monitor - @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ | - EV_WRITE - @param callback callback function to be invoked when the event occurs - @param arg an argument to be passed to the callback function - @param timeout the maximum amount of time to wait for the event, or NULL - to wait forever - @return 0 if successful, or -1 if an error occurred - @see event_once() - */ -int event_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *); - - -/** - Add an event to the set of monitored events. - - The function event_add() schedules the execution of the ev event when the - event specified in event_set() occurs or in at least the time specified in - the tv. If tv is NULL, no timeout occurs and the function will only be - called if a matching event occurs on the file descriptor. The event in the - ev argument must be already initialized by event_set() and may not be used - in calls to event_set() until it has timed out or been removed with - event_del(). If the event in the ev argument already has a scheduled - timeout, the old timeout will be replaced by the new one. - - @param ev an event struct initialized via event_set() - @param timeout the maximum amount of time to wait for the event, or NULL - to wait forever - @return 0 if successful, or -1 if an error occurred - @see event_del(), event_set() - */ -int event_add(struct event *, struct timeval *); - - -/** - Remove an event from the set of monitored events. - - The function event_del() will cancel the event in the argument ev. If the - event has already executed or has never been added the call will have no - effect. - - @param ev an event struct to be removed from the working set - @return 0 if successful, or -1 if an error occurred - @see event_add() - */ -int event_del(struct event *); - -void event_active(struct event *, int, short); - - -/** - Checks if a specific event is pending or scheduled. - - @param ev an event struct previously passed to event_add() - @param event the requested event type; any of EV_TIMEOUT|EV_READ| - EV_WRITE|EV_SIGNAL - @param tv an alternate timeout (FIXME - is this true?) - - @return 1 if the event is pending, or 0 if the event has not occurred - - */ -int event_pending(struct event *, short, struct timeval *); - - -/** - Test if an event structure has been initialized. - - The event_initialized() macro can be used to check if an event has been - initialized. - - @param ev an event structure to be tested - @return 1 if the structure has been initialized, or 0 if it has not been - initialized - */ -#ifdef WIN32 -#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE) -#else -#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT) -#endif - - -/** - Get the libevent version number. - - @return a string containing the version number of libevent - */ -const char *event_get_version(void); - - -/** - Get the kernel event notification mechanism used by libevent. - - @return a string identifying the kernel event mechanism (kqueue, epoll, etc.) - */ -const char *event_get_method(void); - - -/** - Set the number of different event priorities. - - By default libevent schedules all active events with the same priority. - However, some time it is desirable to process some events with a higher - priority than others. For that reason, libevent supports strict priority - queues. Active events with a lower priority are always processed before - events with a higher priority. - - The number of different priorities can be set initially with the - event_priority_init() function. This function should be called before the - first call to event_dispatch(). The event_priority_set() function can be - used to assign a priority to an event. By default, libevent assigns the - middle priority to all events unless their priority is explicitly set. - - @param npriorities the maximum number of priorities - @return 0 if successful, or -1 if an error occurred - @see event_base_priority_init(), event_priority_set() - - */ -int event_priority_init(int); - - -/** - Set the number of different event priorities (threadsafe variant). - - See the description of event_priority_init() for more information. - - @param eb the event_base structure returned by event_init() - @param npriorities the maximum number of priorities - @return 0 if successful, or -1 if an error occurred - @see event_priority_init(), event_priority_set() - */ -int event_base_priority_init(struct event_base *, int); - - -/** - Assign a priority to an event. - - @param ev an event struct - @param priority the new priority to be assigned - @return 0 if successful, or -1 if an error occurred - @see event_priority_init() - */ -int event_priority_set(struct event *, int); - - -/* These functions deal with buffering input and output */ - -struct evbuffer { - u_char *buffer; - u_char *orig_buffer; - - size_t misalign; - size_t totallen; - size_t off; - - void (*cb)(struct evbuffer *, size_t, size_t, void *); - void *cbarg; -}; - -/* Just for error reporting - use other constants otherwise */ -#define EVBUFFER_READ 0x01 -#define EVBUFFER_WRITE 0x02 -#define EVBUFFER_EOF 0x10 -#define EVBUFFER_ERROR 0x20 -#define EVBUFFER_TIMEOUT 0x40 - -struct bufferevent; -typedef void (*evbuffercb)(struct bufferevent *, void *); -typedef void (*everrorcb)(struct bufferevent *, short what, void *); - -struct event_watermark { - size_t low; - size_t high; -}; - -struct bufferevent { - struct event ev_read; - struct event ev_write; - - struct evbuffer *input; - struct evbuffer *output; - - struct event_watermark wm_read; - struct event_watermark wm_write; - - evbuffercb readcb; - evbuffercb writecb; - everrorcb errorcb; - void *cbarg; - - int timeout_read; /* in seconds */ - int timeout_write; /* in seconds */ - - short enabled; /* events that are currently enabled */ -}; - - -/** - Create a new bufferevent. - - libevent provides an abstraction on top of the regular event callbacks. - This abstraction is called a buffered event. A buffered event provides - input and output buffers that get filled and drained automatically. The - user of a buffered event no longer deals directly with the I/O, but - instead is reading from input and writing to output buffers. - - Once initialized, the bufferevent structure can be used repeatedly with - bufferevent_enable() and bufferevent_disable(). - - When read enabled the bufferevent will try to read from the file descriptor - and call the read callback. The write callback is executed whenever the - output buffer is drained below the write low watermark, which is 0 by - default. - - If multiple bases are in use, bufferevent_base_set() must be called before - enabling the bufferevent for the first time. - - @param fd the file descriptor from which data is read and written to. - This file descriptor is not allowed to be a pipe(2). - @param readcb callback to invoke when there is data to be read, or NULL if - no callback is desired - @param writecb callback to invoke when the file descriptor is ready for - writing, or NULL if no callback is desired - @param errorcb callback to invoke when there is an error on the file - descriptor - @param cbarg an argument that will be supplied to each of the callbacks - (readcb, writecb, and errorcb) - @return a pointer to a newly allocated bufferevent struct, or NULL if an - error occurred - @see bufferevent_base_set(), bufferevent_free() - */ -struct bufferevent *bufferevent_new(int fd, - evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg); - - -/** - Assign a bufferevent to a specific event_base. - - @param base an event_base returned by event_init() - @param bufev a bufferevent struct returned by bufferevent_new() - @return 0 if successful, or -1 if an error occurred - @see bufferevent_new() - */ -int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev); - - -/** - Assign a priority to a bufferevent. - - @param bufev a bufferevent struct - @param pri the priority to be assigned - @return 0 if successful, or -1 if an error occurred - */ -int bufferevent_priority_set(struct bufferevent *bufev, int pri); - - -/** - Deallocate the storage associated with a bufferevent structure. - - @param bufev the bufferevent structure to be freed. - */ -void bufferevent_free(struct bufferevent *bufev); - - -/** - Write data to a bufferevent buffer. - - The bufferevent_write() function can be used to write data to the file - descriptor. The data is appended to the output buffer and written to the - descriptor automatically as it becomes available for writing. - - @param bufev the bufferevent to be written to - @param data a pointer to the data to be written - @param size the length of the data, in bytes - @return 0 if successful, or -1 if an error occurred - @see bufferevent_write_buffer() - */ -int bufferevent_write(struct bufferevent *bufev, - const void *data, size_t size); - - -/** - Write data from an evbuffer to a bufferevent buffer. The evbuffer is - being drained as a result. - - @param bufev the bufferevent to be written to - @param buf the evbuffer to be written - @return 0 if successful, or -1 if an error occurred - @see bufferevent_write() - */ -int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf); - - -/** - Read data from a bufferevent buffer. - - The bufferevent_read() function is used to read data from the input buffer. - - @param bufev the bufferevent to be read from - @param data pointer to a buffer that will store the data - @param size the size of the data buffer, in bytes - @return the amount of data read, in bytes. - */ -size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size); - -/** - Enable a bufferevent. - - @param bufev the bufferevent to be enabled - @param event any combination of EV_READ | EV_WRITE. - @return 0 if successful, or -1 if an error occurred - @see bufferevent_disable() - */ -int bufferevent_enable(struct bufferevent *bufev, short event); - - -/** - Disable a bufferevent. - - @param bufev the bufferevent to be disabled - @param event any combination of EV_READ | EV_WRITE. - @return 0 if successful, or -1 if an error occurred - @see bufferevent_enable() - */ -int bufferevent_disable(struct bufferevent *bufev, short event); - - -/** - Set the read and write timeout for a buffered event. - - @param bufev the bufferevent to be modified - @param timeout_read the read timeout - @param timeout_write the write timeout - */ -void bufferevent_settimeout(struct bufferevent *bufev, - int timeout_read, int timeout_write); - - -#define EVBUFFER_LENGTH(x) (x)->off -#define EVBUFFER_DATA(x) (x)->buffer -#define EVBUFFER_INPUT(x) (x)->input -#define EVBUFFER_OUTPUT(x) (x)->output - - -/** - Allocate storage for a new evbuffer. - - @return a pointer to a newly allocated evbuffer struct, or NULL if an error - occurred - */ -struct evbuffer *evbuffer_new(void); - - -/** - Deallocate storage for an evbuffer. - - @param pointer to the evbuffer to be freed - */ -void evbuffer_free(struct evbuffer *); - - -/** - Expands the available space in an event buffer. - - Expands the available space in the event buffer to at least datlen - - @param buf the event buffer to be expanded - @param datlen the new minimum length requirement - @return 0 if successful, or -1 if an error occurred -*/ -int evbuffer_expand(struct evbuffer *, size_t); - - -/** - Append data to the end of an evbuffer. - - @param buf the event buffer to be appended to - @param data pointer to the beginning of the data buffer - @param datlen the number of bytes to be copied from the data buffer - */ -int evbuffer_add(struct evbuffer *, const void *, size_t); - - - -/** - Read data from an event buffer and drain the bytes read. - - @param buf the event buffer to be read from - @param data the destination buffer to store the result - @param datlen the maximum size of the destination buffer - @return the number of bytes read - */ -int evbuffer_remove(struct evbuffer *, void *, size_t); - - -/** - * Read a single line from an event buffer. - * - * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'. - * The returned buffer needs to be freed by the caller. - * - * @param buffer the evbuffer to read from - * @return pointer to a single line, or NULL if an error occurred - */ -char *evbuffer_readline(struct evbuffer *); - - -/** - Move data from one evbuffer into another evbuffer. - - This is a destructive add. The data from one buffer moves into - the other buffer. The destination buffer is expanded as needed. - - @param outbuf the output buffer - @param inbuf the input buffer - @return 0 if successful, or -1 if an error occurred - */ -int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *); - - -/** - Append a formatted string to the end of an evbuffer. - - @param buf the evbuffer that will be appended to - @param fmt a format string - @param ... arguments that will be passed to printf(3) - @return 0 if successful, or -1 if an error occurred - */ -int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) -#endif -; - - -/** - Append a va_list formatted string to the end of an evbuffer. - - @param buf the evbuffer that will be appended to - @param fmt a format string - @param ap a varargs va_list argument array that will be passed to vprintf(3) - @return 0 if successful, or -1 if an error occurred - */ -int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap); - - -/** - Remove a specified number of bytes data from the beginning of an evbuffer. - - @param buf the evbuffer to be drained - @param len the number of bytes to drain from the beginning of the buffer - @return 0 if successful, or -1 if an error occurred - */ -void evbuffer_drain(struct evbuffer *, size_t); - - -/** - Write the contents of an evbuffer to a file descriptor. - - The evbuffer will be drained after the bytes have been successfully written. - - @param buffer the evbuffer to be written and drained - @param fd the file descriptor to be written to - @return the number of bytes written, or -1 if an error occurred - @see evbuffer_read() - */ -int evbuffer_write(struct evbuffer *, int); - - -/** - Read from a file descriptor and store the result in an evbuffer. - - @param buf the evbuffer to store the result - @param fd the file descriptor to read from - @param howmuch the number of bytes to be read - @return the number of bytes read, or -1 if an error occurred - @see evbuffer_write() - */ -int evbuffer_read(struct evbuffer *, int, int); - - -/** - Find a string within an evbuffer. - - @param buffer the evbuffer to be searched - @param what the string to be searched for - @param len the length of the search string - @return a pointer to the beginning of the search string, or NULL if the search failed. - */ -u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t); - -/** - Set a callback to invoke when the evbuffer is modified. - - @param buffer the evbuffer to be monitored - @param cb the callback function to invoke when the evbuffer is modified - @param cbarg an argument to be provided to the callback function - */ -void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *); - -/* - * Marshaling tagged data - We assume that all tags are inserted in their - * numeric order - so that unknown tags will always be higher than the - * known ones - and we can just ignore the end of an event buffer. - */ - -void evtag_init(void); - -void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data, - ev_uint32_t len); - -/** - Encode an integer and store it in an evbuffer. - - We encode integer's by nibbles; the first nibble contains the number - of significant nibbles - 1; this allows us to encode up to 64-bit - integers. This function is byte-order independent. - - @param evbuf evbuffer to store the encoded number - @param number a 32-bit integer - */ -void encode_int(struct evbuffer *evbuf, ev_uint32_t number); - -void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, - ev_uint32_t integer); - -void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, - const char *string); - -void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, - struct timeval *tv); - -int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, - struct evbuffer *dst); -int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag); -int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength); -int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength); -int evtag_consume(struct evbuffer *evbuf); - -int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, - ev_uint32_t *pinteger); - -int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, - void *data, size_t len); - -int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, - char **pstring); - -int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, - struct timeval *ptv); - -#ifdef __cplusplus -} -#endif - -#endif /* _EVENT_H_ */ diff --git a/extra/libevent/event_tagging.c b/extra/libevent/event_tagging.c deleted file mode 100644 index c67ea8a57af..00000000000 --- a/extra/libevent/event_tagging.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <winsock2.h> -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -#else -#include <sys/ioctl.h> -#endif - -#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> -#ifndef WIN32 -#include <syslog.h> -#endif -#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(data)); - while (number) { - if (off & 0x1) - data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); - else - data[off/2] = (data[off/2] & 0x0f) | - ((number & 0x0f) << 4); - number >>= 4; - off++; - } - - if (off > 2) - nibbles = off - 2; - - /* Off - 1 is the number of encoded nibbles */ - data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4); - - evbuffer_add(evbuf, data, (off + 1) / 2); -} - -/* - * Support variable length encoding of tags; we use the high bit in each - * octet as a continuation signal. - */ - -int -evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag) -{ - int bytes = 0; - ev_uint8_t data[5]; - - memset(data, 0, sizeof(data)); - do { - ev_uint8_t lower = tag & 0x7f; - tag >>= 7; - - if (tag) - lower |= 0x80; - - data[bytes++] = lower; - } while (tag); - - if (evbuf != NULL) - evbuffer_add(evbuf, data, bytes); - - return (bytes); -} - -static int -decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain) -{ - ev_uint32_t number = 0; - ev_uint8_t *data = EVBUFFER_DATA(evbuf); - int len = EVBUFFER_LENGTH(evbuf); - int count = 0, shift = 0, done = 0; - - while (count++ < len) { - ev_uint8_t lower = *data++; - number |= (lower & 0x7f) << shift; - shift += 7; - - if (!(lower & 0x80)) { - done = 1; - break; - } - } - - if (!done) - return (-1); - - if (dodrain) - evbuffer_drain(evbuf, count); - - if (ptag != NULL) - *ptag = number; - - return (count); -} - -int -evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf) -{ - return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */)); -} - -/* - * Marshal a data type, the general format is as follows: - * - * tag number: one byte; length: var bytes; payload: var bytes - */ - -void -evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, - const void *data, ev_uint32_t len) -{ - evtag_encode_tag(evbuf, tag); - encode_int(evbuf, len); - evbuffer_add(evbuf, (void *)data, len); -} - -/* Marshaling for integers */ -void -evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer) -{ - evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); - encode_int(_buf, integer); - - evtag_encode_tag(evbuf, tag); - encode_int(evbuf, EVBUFFER_LENGTH(_buf)); - evbuffer_add_buffer(evbuf, _buf); -} - -void -evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string) -{ - evtag_marshal(buf, tag, string, strlen(string)); -} - -void -evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv) -{ - evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); - - encode_int(_buf, tv->tv_sec); - encode_int(_buf, tv->tv_usec); - - evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), - EVBUFFER_LENGTH(_buf)); -} - -static int -decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain) -{ - ev_uint32_t number = 0; - ev_uint8_t *data = EVBUFFER_DATA(evbuf); - int len = EVBUFFER_LENGTH(evbuf); - int nibbles = 0; - - if (!len) - return (-1); - - nibbles = ((data[0] & 0xf0) >> 4) + 1; - if (nibbles > 8 || (nibbles >> 1) + 1 > len) - return (-1); - len = (nibbles >> 1) + 1; - - while (nibbles > 0) { - number <<= 4; - if (nibbles & 0x1) - number |= data[nibbles >> 1] & 0x0f; - else - number |= (data[nibbles >> 1] & 0xf0) >> 4; - nibbles--; - } - - if (dodrain) - evbuffer_drain(evbuf, len); - - *pnumber = number; - - return (len); -} - -int -evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf) -{ - return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0); -} - -int -evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag) -{ - return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */)); -} - -int -evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength) -{ - struct evbuffer tmp; - int res, len; - - len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); - if (len == -1) - return (-1); - - tmp = *evbuf; - tmp.buffer += len; - tmp.off -= len; - - res = decode_int_internal(plength, &tmp, 0); - if (res == -1) - return (-1); - - *plength += res + len; - - return (0); -} - -int -evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength) -{ - struct evbuffer tmp; - int res, len; - - len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */); - if (len == -1) - return (-1); - - tmp = *evbuf; - tmp.buffer += len; - tmp.off -= len; - - res = decode_int_internal(plength, &tmp, 0); - if (res == -1) - return (-1); - - return (0); -} - -int -evtag_consume(struct evbuffer *evbuf) -{ - ev_uint32_t len; - if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1) - return (-1); - if (evtag_decode_int(&len, evbuf) == -1) - return (-1); - evbuffer_drain(evbuf, len); - - return (0); -} - -/* Reads the data type from an event buffer */ - -int -evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst) -{ - ev_uint32_t len; - ev_uint32_t integer; - - if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1) - return (-1); - if (evtag_decode_int(&integer, src) == -1) - return (-1); - len = integer; - - if (EVBUFFER_LENGTH(src) < len) - return (-1); - - if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1) - return (-1); - - evbuffer_drain(src, len); - - return (len); -} - -/* Marshaling for integers */ - -int -evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag, - ev_uint32_t *pinteger) -{ - ev_uint32_t tag; - ev_uint32_t len; - ev_uint32_t integer; - - if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1) - return (-1); - if (need_tag != tag) - return (-1); - if (evtag_decode_int(&integer, evbuf) == -1) - return (-1); - len = integer; - - if (EVBUFFER_LENGTH(evbuf) < len) - return (-1); - - evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); - if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1) - return (-1); - - evbuffer_drain(evbuf, len); - - return (evtag_decode_int(pinteger, _buf)); -} - -/* Unmarshal a fixed length tag */ - -int -evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data, - size_t len) -{ - ev_uint32_t tag; - - /* Initialize this event buffer so that we can read into it */ - evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); - - /* Now unmarshal a tag and check that it matches the tag we want */ - if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag) - return (-1); - - if (EVBUFFER_LENGTH(_buf) != len) - return (-1); - - memcpy(data, EVBUFFER_DATA(_buf), len); - return (0); -} - -int -evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag, - char **pstring) -{ - ev_uint32_t tag; - - evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); - - if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag) - return (-1); - - *pstring = calloc(EVBUFFER_LENGTH(_buf) + 1, 1); - if (*pstring == NULL) - event_err(1, "%s: calloc", __func__); - evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf)); - - return (0); -} - -int -evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag, - struct timeval *ptv) -{ - ev_uint32_t tag; - ev_uint32_t integer; - - evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf)); - if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag) - return (-1); - - if (evtag_decode_int(&integer, _buf) == -1) - return (-1); - ptv->tv_sec = integer; - if (evtag_decode_int(&integer, _buf) == -1) - return (-1); - ptv->tv_usec = integer; - - return (0); -} diff --git a/extra/libevent/evhttp.h b/extra/libevent/evhttp.h deleted file mode 100644 index c20b1a7165e..00000000000 --- a/extra/libevent/evhttp.h +++ /dev/null @@ -1,340 +0,0 @@ -/* - * 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 - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winsock2.h> -#undef WIN32_LEAN_AND_MEAN -#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); - -/** - * 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 got_firstline; - 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 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. - * The arguments are separated by key and value. - * URI should already be decoded. - */ -void evhttp_parse_query(const char *uri, struct evkeyvalq *); - - -/** - * 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_ */ diff --git a/extra/libevent/evport.c b/extra/libevent/evport.c deleted file mode 100644 index c3250531d45..00000000000 --- a/extra/libevent/evport.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Submitted by David Pacheco (dp.spambait@gmail.com) - * - * 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 SUN MICROSYSTEMS, INC. ``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 SUN MICROSYSTEMS, INC. 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. - */ - -/* - * Copyright (c) 2007 Sun Microsystems. All rights reserved. - * Use is subject to license terms. - */ - -/* - * evport.c: event backend using Solaris 10 event ports. See port_create(3C). - * This implementation is loosely modeled after the one used for select(2) (in - * select.c). - * - * The outstanding events are tracked in a data structure called evport_data. - * Each entry in the ed_fds array corresponds to a file descriptor, and contains - * pointers to the read and write events that correspond to that fd. (That is, - * when the file is readable, the "read" event should handle it, etc.) - * - * evport_add and evport_del update this data structure. evport_dispatch uses it - * to determine where to callback when an event occurs (which it gets from - * port_getn). - * - * Helper functions are used: grow() grows the file descriptor array as - * necessary when large fd's come in. reassociate() takes care of maintaining - * the proper file-descriptor/event-port associations. - * - * As in the select(2) implementation, signals are handled by evsignal. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_EVENT_PORTS - -#include <sys/time.h> -#include <assert.h> -#include <sys/queue.h> -#include <errno.h> -#include <poll.h> -#include <port.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#ifdef CHECK_INVARIANTS -#include <assert.h> -#endif - -#include "event.h" -#include "event-internal.h" -#include "log.h" -#include "evsignal.h" - - -/* - * Default value for ed_nevents, which is the maximum file descriptor number we - * can handle. If an event comes in for a file descriptor F > nevents, we will - * grow the array of file descriptors, doubling its size. - */ -#define DEFAULT_NFDS 16 - - -/* - * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on - * any particular call. You can speed things up by increasing this, but it will - * (obviously) require more memory. - */ -#define EVENTS_PER_GETN 8 - -/* - * Per-file-descriptor information about what events we're subscribed to. These - * fields are NULL if no event is subscribed to either of them. - */ - -struct fd_info { - struct event* fdi_revt; /* the event responsible for the "read" */ - struct event* fdi_wevt; /* the event responsible for the "write" */ -}; - -#define FDI_HAS_READ(fdi) ((fdi)->fdi_revt != NULL) -#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL) -#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi)) -#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \ - (FDI_HAS_WRITE(fdi) ? POLLOUT : 0) - -struct evport_data { - int ed_port; /* event port for system events */ - int ed_nevents; /* number of allocated fdi's */ - struct fd_info *ed_fds; /* allocated fdi table */ - /* fdi's that we need to reassoc */ - int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */ -}; - -static void* evport_init (struct event_base *); -static int evport_add (void *, struct event *); -static int evport_del (void *, struct event *); -static int evport_dispatch (struct event_base *, void *, struct timeval *); -static void evport_dealloc (struct event_base *, void *); - -const struct eventop evportops = { - "event ports", - evport_init, - evport_add, - evport_del, - evport_dispatch, - evport_dealloc, - 1 /* need reinit */ -}; - -/* - * Initialize the event port implementation. - */ - -static void* -evport_init(struct event_base *base) -{ - struct evport_data *evpd; - int i; - /* - * Disable event ports when this environment variable is set - */ - if (getenv("EVENT_NOEVPORT")) - return (NULL); - - if (!(evpd = calloc(1, sizeof(struct evport_data)))) - return (NULL); - - if ((evpd->ed_port = port_create()) == -1) { - free(evpd); - return (NULL); - } - - /* - * Initialize file descriptor structure - */ - evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info)); - if (evpd->ed_fds == NULL) { - close(evpd->ed_port); - free(evpd); - return (NULL); - } - evpd->ed_nevents = DEFAULT_NFDS; - for (i = 0; i < EVENTS_PER_GETN; i++) - evpd->ed_pending[i] = -1; - - evsignal_init(base); - - return (evpd); -} - -#ifdef CHECK_INVARIANTS -/* - * Checks some basic properties about the evport_data structure. Because it - * checks all file descriptors, this function can be expensive when the maximum - * file descriptor ever used is rather large. - */ - -static void -check_evportop(struct evport_data *evpd) -{ - assert(evpd); - assert(evpd->ed_nevents > 0); - assert(evpd->ed_port > 0); - assert(evpd->ed_fds > 0); - - /* - * Verify the integrity of the fd_info struct as well as the events to - * which it points (at least, that they're valid references and correct - * for their position in the structure). - */ - int i; - for (i = 0; i < evpd->ed_nevents; ++i) { - struct event *ev; - struct fd_info *fdi; - - fdi = &evpd->ed_fds[i]; - if ((ev = fdi->fdi_revt) != NULL) { - assert(ev->ev_fd == i); - } - if ((ev = fdi->fdi_wevt) != NULL) { - assert(ev->ev_fd == i); - } - } -} - -/* - * Verifies very basic integrity of a given port_event. - */ -static void -check_event(port_event_t* pevt) -{ - /* - * We've only registered for PORT_SOURCE_FD events. The only - * other thing we can legitimately receive is PORT_SOURCE_ALERT, - * but since we're not using port_alert either, we can assume - * PORT_SOURCE_FD. - */ - assert(pevt->portev_source == PORT_SOURCE_FD); - assert(pevt->portev_user == NULL); -} - -#else -#define check_evportop(epop) -#define check_event(pevt) -#endif /* CHECK_INVARIANTS */ - -/* - * Doubles the size of the allocated file descriptor array. - */ -static int -grow(struct evport_data *epdp, int factor) -{ - struct fd_info *tmp; - int oldsize = epdp->ed_nevents; - int newsize = factor * oldsize; - assert(factor > 1); - - check_evportop(epdp); - - tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize); - if (NULL == tmp) - return -1; - epdp->ed_fds = tmp; - memset((char*) (epdp->ed_fds + oldsize), 0, - (newsize - oldsize)*sizeof(struct fd_info)); - epdp->ed_nevents = newsize; - - check_evportop(epdp); - - return 0; -} - - -/* - * (Re)associates the given file descriptor with the event port. The OS events - * are specified (implicitly) from the fd_info struct. - */ -static int -reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd) -{ - int sysevents = FDI_TO_SYSEVENTS(fdip); - - if (sysevents != 0) { - if (port_associate(epdp->ed_port, PORT_SOURCE_FD, - fd, sysevents, NULL) == -1) { - event_warn("port_associate"); - return (-1); - } - } - - check_evportop(epdp); - - return (0); -} - -/* - * Main event loop - polls port_getn for some number of events, and processes - * them. - */ - -static int -evport_dispatch(struct event_base *base, void *arg, struct timeval *tv) -{ - int i, res; - struct evport_data *epdp = arg; - port_event_t pevtlist[EVENTS_PER_GETN]; - - /* - * port_getn will block until it has at least nevents events. It will - * also return how many it's given us (which may be more than we asked - * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in - * nevents. - */ - int nevents = 1; - - /* - * We have to convert a struct timeval to a struct timespec - * (only difference is nanoseconds vs. microseconds). If no time-based - * events are active, we should wait for I/O (and tv == NULL). - */ - struct timespec ts; - struct timespec *ts_p = NULL; - if (tv != NULL) { - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000; - ts_p = &ts; - } - - /* - * Before doing anything else, we need to reassociate the events we hit - * last time which need reassociation. See comment at the end of the - * loop below. - */ - for (i = 0; i < EVENTS_PER_GETN; ++i) { - struct fd_info *fdi = NULL; - if (epdp->ed_pending[i] != -1) { - fdi = &(epdp->ed_fds[epdp->ed_pending[i]]); - } - - if (fdi != NULL && FDI_HAS_EVENTS(fdi)) { - int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd : - fdi->fdi_wevt->ev_fd; - reassociate(epdp, fdi, fd); - epdp->ed_pending[i] = -1; - } - } - - if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN, - (unsigned int *) &nevents, ts_p)) == -1) { - if (errno == EINTR || errno == EAGAIN) { - evsignal_process(base); - return (0); - } else if (errno == ETIME) { - if (nevents == 0) - return (0); - } else { - event_warn("port_getn"); - return (-1); - } - } else if (base->sig.evsignal_caught) { - evsignal_process(base); - } - - event_debug(("%s: port_getn reports %d events", __func__, nevents)); - - for (i = 0; i < nevents; ++i) { - struct event *ev; - struct fd_info *fdi; - port_event_t *pevt = &pevtlist[i]; - int fd = (int) pevt->portev_object; - - check_evportop(epdp); - check_event(pevt); - epdp->ed_pending[i] = fd; - - /* - * Figure out what kind of event it was - * (because we have to pass this to the callback) - */ - res = 0; - if (pevt->portev_events & POLLIN) - res |= EV_READ; - if (pevt->portev_events & POLLOUT) - res |= EV_WRITE; - - assert(epdp->ed_nevents > fd); - fdi = &(epdp->ed_fds[fd]); - - /* - * We now check for each of the possible events (READ - * or WRITE). Then, we activate the event (which will - * cause its callback to be executed). - */ - - if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) { - event_active(ev, res, 1); - } - - if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) { - event_active(ev, res, 1); - } - } /* end of all events gotten */ - - check_evportop(epdp); - - return (0); -} - - -/* - * Adds the given event (so that you will be notified when it happens via - * the callback function). - */ - -static int -evport_add(void *arg, struct event *ev) -{ - struct evport_data *evpd = arg; - struct fd_info *fdi; - int factor; - - check_evportop(evpd); - - /* - * Delegate, if it's not ours to handle. - */ - if (ev->ev_events & EV_SIGNAL) - return (evsignal_add(ev)); - - /* - * If necessary, grow the file descriptor info table - */ - - factor = 1; - while (ev->ev_fd >= factor * evpd->ed_nevents) - factor *= 2; - - if (factor > 1) { - if (-1 == grow(evpd, factor)) { - return (-1); - } - } - - fdi = &evpd->ed_fds[ev->ev_fd]; - if (ev->ev_events & EV_READ) - fdi->fdi_revt = ev; - if (ev->ev_events & EV_WRITE) - fdi->fdi_wevt = ev; - - return reassociate(evpd, fdi, ev->ev_fd); -} - -/* - * Removes the given event from the list of events to wait for. - */ - -static int -evport_del(void *arg, struct event *ev) -{ - struct evport_data *evpd = arg; - struct fd_info *fdi; - int i; - int associated = 1; - - check_evportop(evpd); - - /* - * Delegate, if it's not ours to handle - */ - if (ev->ev_events & EV_SIGNAL) { - return (evsignal_del(ev)); - } - - if (evpd->ed_nevents < ev->ev_fd) { - return (-1); - } - - for (i = 0; i < EVENTS_PER_GETN; ++i) { - if (evpd->ed_pending[i] == ev->ev_fd) { - associated = 0; - break; - } - } - - fdi = &evpd->ed_fds[ev->ev_fd]; - if (ev->ev_events & EV_READ) - fdi->fdi_revt = NULL; - if (ev->ev_events & EV_WRITE) - fdi->fdi_wevt = NULL; - - if (associated) { - if (!FDI_HAS_EVENTS(fdi) && - port_dissociate(evpd->ed_port, PORT_SOURCE_FD, - ev->ev_fd) == -1) { - /* - * Ignre EBADFD error the fd could have been closed - * before event_del() was called. - */ - if (errno != EBADFD) { - event_warn("port_dissociate"); - return (-1); - } - } else { - if (FDI_HAS_EVENTS(fdi)) { - return (reassociate(evpd, fdi, ev->ev_fd)); - } - } - } else { - if (fdi->fdi_revt == NULL && fdi->fdi_wevt == NULL) { - evpd->ed_pending[i] = -1; - } - } - return 0; -} - - -static void -evport_dealloc(struct event_base *base, void *arg) -{ - struct evport_data *evpd = arg; - - evsignal_dealloc(base); - - close(evpd->ed_port); - - if (evpd->ed_fds) - free(evpd->ed_fds); - free(evpd); -} - -#endif /* HAVE_EVENT_PORTS */ diff --git a/extra/libevent/evrpc-internal.h b/extra/libevent/evrpc-internal.h deleted file mode 100644 index c900f959f97..00000000000 --- a/extra/libevent/evrpc-internal.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _EVRPC_INTERNAL_H_ -#define _EVRPC_INTERNAL_H_ - -#include "http-internal.h" - -struct evrpc; - -#define EVRPC_URI_PREFIX "/.rpc." - -struct evrpc_hook { - TAILQ_ENTRY(evrpc_hook) (next); - - /* returns -1; if the rpc should be aborted, is allowed to rewrite */ - int (*process)(struct evhttp_request *, struct evbuffer *, void *); - void *process_arg; -}; - -TAILQ_HEAD(evrpc_hook_list, evrpc_hook); - -/* - * this is shared between the base and the pool, so that we can reuse - * the hook adding functions; we alias both evrpc_pool and evrpc_base - * to this common structure. - */ -struct _evrpc_hooks { - /* hooks for processing outbound and inbound rpcs */ - struct evrpc_hook_list in_hooks; - struct evrpc_hook_list out_hooks; -}; - -#define input_hooks common.in_hooks -#define output_hooks common.out_hooks - -struct evrpc_base { - struct _evrpc_hooks common; - - /* the HTTP server under which we register our RPC calls */ - struct evhttp* http_server; - - /* a list of all RPCs registered with us */ - TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs; -}; - -struct evrpc_req_generic; -void evrpc_reqstate_free(struct evrpc_req_generic* rpc_state); - -/* A pool for holding evhttp_connection objects */ -struct evrpc_pool { - struct _evrpc_hooks common; - - struct event_base *base; - - struct evconq connections; - - int timeout; - - TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) requests; -}; - - -#endif /* _EVRPC_INTERNAL_H_ */ diff --git a/extra/libevent/evrpc.c b/extra/libevent/evrpc.c deleted file mode 100644 index bfe3087ef8a..00000000000 --- a/extra/libevent/evrpc.c +++ /dev/null @@ -1,658 +0,0 @@ -/* - * 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. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winsock2.h> -#undef WIN32_LEAN_AND_MEAN -#include "misc.h" -#endif - -#include <sys/types.h> -#ifndef WIN32 -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#include <sys/queue.h> -#include <stdio.h> -#include <stdlib.h> -#ifndef WIN32 -#include <unistd.h> -#endif -#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, INPUT, hook)); - } - while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) { - assert(evrpc_remove_hook(base, 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 INPUT: - head = &base->in_hooks; - break; - case OUTPUT: - head = &base->out_hooks; - break; - default: - assert(hook_type == INPUT || hook_type == 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 INPUT: - head = &base->in_hooks; - break; - case OUTPUT: - head = &base->out_hooks; - break; - default: - assert(hook_type == INPUT || hook_type == 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, INPUT, hook)); - } - - while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) { - assert(evrpc_remove_hook(pool, OUTPUT, hook)); - } - - free(pool); -} - -/* - * Add a connection to the RPC pool. A request scheduled on the pool - * may use any available connection. - */ - -void -evrpc_pool_add_connection(struct evrpc_pool *pool, - struct evhttp_connection *connection) { - assert(connection->http_server == NULL); - TAILQ_INSERT_TAIL(&pool->connections, connection, next); - - /* - * associate an event base with this connection - */ - if (pool->base != NULL) - evhttp_connection_set_base(connection, pool->base); - - /* - * unless a timeout was specifically set for a connection, - * the connection inherits the timeout from the pool. - */ - if (connection->timeout == -1) - connection->timeout = pool->timeout; - - /* - * if we have any requests pending, schedule them with the new - * connections. - */ - - if (TAILQ_FIRST(&pool->requests) != NULL) { - struct evrpc_request_wrapper *request = - TAILQ_FIRST(&pool->requests); - TAILQ_REMOVE(&pool->requests, request, next); - evrpc_schedule_request(connection, request); - } -} - -void -evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs) -{ - struct evhttp_connection *evcon; - TAILQ_FOREACH(evcon, &pool->connections, next) { - evcon->timeout = timeout_in_secs; - } - pool->timeout = timeout_in_secs; -} - - -static void evrpc_reply_done(struct evhttp_request *, void *); -static void evrpc_request_timeout(int, short, void *); - -/* - * Finds a connection object associated with the pool that is currently - * idle and can be used to make a request. - */ -static struct evhttp_connection * -evrpc_pool_find_connection(struct evrpc_pool *pool) -{ - struct evhttp_connection *connection; - TAILQ_FOREACH(connection, &pool->connections, next) { - if (TAILQ_FIRST(&connection->requests) == NULL) - return (connection); - } - - return (NULL); -} - -/* - * We assume that the ctx is no longer queued on the pool. - */ -static int -evrpc_schedule_request(struct evhttp_connection *connection, - struct evrpc_request_wrapper *ctx) -{ - struct evhttp_request *req = NULL; - struct evrpc_pool *pool = ctx->pool; - struct evrpc_status status; - char *uri = NULL; - int res = 0; - - if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL) - goto error; - - /* serialize the request data into the output buffer */ - ctx->request_marshal(req->output_buffer, ctx->request); - - uri = evrpc_construct_uri(ctx->name); - if (uri == NULL) - goto error; - - /* we need to know the connection that we might have to abort */ - ctx->evcon = connection; - - /* apply hooks to the outgoing request */ - if (evrpc_process_hooks(&pool->output_hooks, - req, req->output_buffer) == -1) - goto error; - - if (pool->timeout > 0) { - /* - * a timeout after which the whole rpc is going to be aborted. - */ - struct timeval tv; - evutil_timerclear(&tv); - tv.tv_sec = pool->timeout; - evtimer_add(&ctx->ev_timeout, &tv); - } - - /* start the request over the connection */ - res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri); - free(uri); - - if (res == -1) - goto error; - - return (0); - -error: - memset(&status, 0, sizeof(status)); - status.error = EVRPC_STATUS_ERR_UNSTARTED; - (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg); - evrpc_request_wrapper_free(ctx); - return (-1); -} - -int -evrpc_make_request(struct evrpc_request_wrapper *ctx) -{ - struct evrpc_pool *pool = ctx->pool; - - /* initialize the event structure for this rpc */ - evtimer_set(&ctx->ev_timeout, evrpc_request_timeout, ctx); - if (pool->base != NULL) - event_base_set(pool->base, &ctx->ev_timeout); - - /* we better have some available connections on the pool */ - assert(TAILQ_FIRST(&pool->connections) != NULL); - - /* - * if no connection is available, we queue the request on the pool, - * the next time a connection is empty, the rpc will be send on that. - */ - TAILQ_INSERT_TAIL(&pool->requests, ctx, next); - - evrpc_pool_schedule(pool); - - return (0); -} - -static void -evrpc_reply_done(struct evhttp_request *req, void *arg) -{ - struct evrpc_request_wrapper *ctx = arg; - struct evrpc_pool *pool = ctx->pool; - struct evrpc_status status; - int res = -1; - - /* cancel any timeout we might have scheduled */ - event_del(&ctx->ev_timeout); - - memset(&status, 0, sizeof(status)); - status.http_req = req; - - /* we need to get the reply now */ - if (req != NULL) { - /* apply hooks to the incoming request */ - if (evrpc_process_hooks(&pool->input_hooks, - req, req->input_buffer) == -1) { - status.error = EVRPC_STATUS_ERR_HOOKABORTED; - res = -1; - } else { - res = ctx->reply_unmarshal(ctx->reply, - req->input_buffer); - if (res == -1) { - status.error = EVRPC_STATUS_ERR_BADPAYLOAD; - } - } - } else { - status.error = EVRPC_STATUS_ERR_TIMEOUT; - } - - if (res == -1) { - /* clear everything that we might have written previously */ - ctx->reply_clear(ctx->reply); - } - - (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg); - - evrpc_request_wrapper_free(ctx); - - /* the http layer owns the request structure */ - - /* see if we can schedule another request */ - evrpc_pool_schedule(pool); -} - -static void -evrpc_pool_schedule(struct evrpc_pool *pool) -{ - struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests); - struct evhttp_connection *evcon; - - /* if no requests are pending, we have no work */ - if (ctx == NULL) - return; - - if ((evcon = evrpc_pool_find_connection(pool)) != NULL) { - TAILQ_REMOVE(&pool->requests, ctx, next); - evrpc_schedule_request(evcon, ctx); - } -} - -static void -evrpc_request_timeout(int fd, short what, void *arg) -{ - struct evrpc_request_wrapper *ctx = arg; - struct evhttp_connection *evcon = ctx->evcon; - assert(evcon != NULL); - - evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); -} diff --git a/extra/libevent/evrpc.h b/extra/libevent/evrpc.h deleted file mode 100644 index 45f684ac5ac..00000000000 --- a/extra/libevent/evrpc.h +++ /dev/null @@ -1,477 +0,0 @@ -/* - * 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 { - INPUT, /**< apply the function to an input hook */ - OUTPUT /**< apply the function to an output hook */ -}; - -/** adds a processing hook to either an rpc base or rpc pool - * - * If a hook returns -1, the processing is aborted. - * - * The add functions return handles that can be used for removing hooks. - * - * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool - * @param hook_type either INPUT or OUTPUT - * @param cb the callback to call when the hook is activated - * @param cb_arg an additional argument for the callback - * @return a handle to the hook so it can be removed later - * @see evrpc_remove_hook() - */ -void *evrpc_add_hook(void *vbase, - enum EVRPC_HOOK_TYPE hook_type, - int (*cb)(struct evhttp_request *, struct evbuffer *, void *), - void *cb_arg); - -/** removes a previously added hook - * - * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool - * @param hook_type either INPUT or OUTPUT - * @param handle a handle returned by evrpc_add_hook() - * @return 1 on success or 0 on failure - * @see evrpc_add_hook() - */ -int evrpc_remove_hook(void *vbase, - enum EVRPC_HOOK_TYPE hook_type, - void *handle); - -#ifdef __cplusplus -} -#endif - -#endif /* _EVRPC_H_ */ diff --git a/extra/libevent/evsignal.h b/extra/libevent/evsignal.h deleted file mode 100644 index 0d1e83140bd..00000000000 --- a/extra/libevent/evsignal.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. 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_list signalqueue; - struct event ev_signal; - int ev_signal_pair[2]; - int ev_signal_added; - volatile sig_atomic_t evsignal_caught; - sig_atomic_t evsigcaught[NSIG]; -#ifdef HAVE_SIGACTION - struct sigaction **sh_old; -#else - ev_sighandler_t **sh_old; -#endif - int sh_old_max; -}; -void evsignal_init(struct event_base *); -void evsignal_process(struct event_base *); -int evsignal_add(struct event *); -int evsignal_del(struct event *); -void evsignal_dealloc(struct event_base *); - -#endif /* _EVSIGNAL_H_ */ diff --git a/extra/libevent/evutil.c b/extra/libevent/evutil.c deleted file mode 100644 index 1202d354fe4..00000000000 --- a/extra/libevent/evutil.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -#include <winsock2.h> -#include "misc.h" -#endif - -#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]) -{ -#ifndef WIN32 - return socketpair(family, type, protocol, fd); -#else - /* This code is originally from Tor. Used with permission. */ - - /* This socketpair does not work when localhost is down. So - * it's really not the same thing at all. But it's close enough - * for now, and really, when localhost is down sometimes, we - * have other problems too. - */ - int listener = -1; - int connector = -1; - int acceptor = -1; - struct sockaddr_in listen_addr; - struct sockaddr_in connect_addr; - int size; - int saved_errno = -1; - - if (protocol -#ifdef AF_UNIX - || family != AF_UNIX -#endif - ) { - EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT); - return -1; - } - if (!fd) { - EVUTIL_SET_SOCKET_ERROR(WSAEINVAL); - return -1; - } - - listener = (int)socket(AF_INET, type, 0); - if (listener < 0) - return -1; - memset(&listen_addr, 0, sizeof(listen_addr)); - listen_addr.sin_family = AF_INET; - listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - listen_addr.sin_port = 0; /* kernel chooses port. */ - if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr)) - == -1) - goto tidy_up_and_fail; - if (listen(listener, 1) == -1) - goto tidy_up_and_fail; - - connector = (int)socket(AF_INET, type, 0); - if (connector < 0) - goto tidy_up_and_fail; - /* We want to find out the port number to connect to. */ - size = sizeof(connect_addr); - if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1) - goto tidy_up_and_fail; - if (size != sizeof (connect_addr)) - goto abort_tidy_up_and_fail; - if (connect(connector, (struct sockaddr *) &connect_addr, - sizeof(connect_addr)) == -1) - goto tidy_up_and_fail; - - size = sizeof(listen_addr); - acceptor = (int)accept(listener, (struct sockaddr *) &listen_addr, &size); - if (acceptor < 0) - goto tidy_up_and_fail; - if (size != sizeof(listen_addr)) - goto abort_tidy_up_and_fail; - EVUTIL_CLOSESOCKET(listener); - /* Now check we are talking to ourself by matching port and host on the - two sockets. */ - if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1) - goto tidy_up_and_fail; - if (size != sizeof (connect_addr) - || listen_addr.sin_family != connect_addr.sin_family - || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr - || listen_addr.sin_port != connect_addr.sin_port) - goto abort_tidy_up_and_fail; - fd[0] = connector; - fd[1] = acceptor; - - return 0; - - abort_tidy_up_and_fail: - saved_errno = WSAECONNABORTED; - tidy_up_and_fail: - if (saved_errno < 0) - saved_errno = WSAGetLastError(); - if (listener != -1) - EVUTIL_CLOSESOCKET(listener); - if (connector != -1) - EVUTIL_CLOSESOCKET(connector); - if (acceptor != -1) - EVUTIL_CLOSESOCKET(acceptor); - - EVUTIL_SET_SOCKET_ERROR(saved_errno); - return -1; -#endif -} - -int -evutil_make_socket_nonblocking(int fd) -{ -#ifdef WIN32 - { - unsigned long nonblocking = 1; - ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking); - } -#else - if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - event_warn("fcntl(O_NONBLOCK)"); - return -1; -} -#endif - 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); -#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300 - /* XXXX on old versions of MS APIs, we only support base - * 10. */ - ev_int64_t r; - if (base != 10) - return 0; - r = (ev_int64_t) _atoi64(s); - while (isspace(*s)) - ++s; - while (isdigit(*s)) - ++s; - if (endptr) - *endptr = (char*) s; - return r; -#elif defined(WIN32) - return (ev_int64_t) _strtoi64(s, endptr, base); -#else -#error "I don't know how to parse 64-bit integers." -#endif -} diff --git a/extra/libevent/evutil.h b/extra/libevent/evutil.h deleted file mode 100644 index 2cfcacb2e0e..00000000000 --- a/extra/libevent/evutil.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 <event-config.h> -#ifdef _EVENT_HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef _EVENT_HAVE_STDINT_H -#include <stdint.h> -#elif defined(_EVENT_HAVE_INTTYPES_H) -#include <inttypes.h> -#endif -#ifdef _EVENT_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#ifdef _EVENT_HAVE_UINT64_T -#define ev_uint64_t uint64_t -#define ev_int64_t int64_t -#elif defined(WIN32) -#define ev_uint64_t unsigned __int64 -#define ev_int64_t __int64 -#elif _EVENT_SIZEOF_LONG_LONG == 8 -#define ev_uint64_t unsigned long long -#define ev_int64_t long long -#elif _EVENT_SIZEOF_LONG == 8 -#define ev_uint64_t unsigned long -#define ev_int64_t long -#else -#error "No way to define ev_uint64_t" -#endif - -#ifdef _EVENT_HAVE_UINT32_T -#define ev_uint32_t uint32_t -#elif defined(WIN32) -#define ev_uint32_t unsigned int -#elif _EVENT_SIZEOF_LONG == 4 -#define ev_uint32_t unsigned long -#elif _EVENT_SIZEOF_INT == 4 -#define ev_uint32_t unsigned int -#else -#error "No way to define ev_uint32_t" -#endif - -#ifdef _EVENT_HAVE_UINT16_T -#define ev_uint16_t uint16_t -#elif defined(WIN32) -#define ev_uint16_t unsigned short -#elif _EVENT_SIZEOF_INT == 2 -#define ev_uint16_t unsigned int -#elif _EVENT_SIZEOF_SHORT == 2 -#define ev_uint16_t unsigned short -#else -#error "No way to define ev_uint16_t" -#endif - -#ifdef _EVENT_HAVE_UINT8_T -#define ev_uint8_t uint8_t -#else -#define ev_uint8_t unsigned char -#endif - -int evutil_socketpair(int d, int type, int protocol, int sv[2]); -int evutil_make_socket_nonblocking(int sock); -#ifdef WIN32 -#define EVUTIL_CLOSESOCKET(s) closesocket(s) -#else -#define EVUTIL_CLOSESOCKET(s) close(s) -#endif - -#ifdef WIN32 -#define EVUTIL_SOCKET_ERROR() WSAGetLastError() -#define EVUTIL_SET_SOCKET_ERROR(errcode) \ - do { WSASetLastError(errcode); } while (0) -#else -#define EVUTIL_SOCKET_ERROR() (errno) -#define EVUTIL_SET_SOCKET_ERROR(errcode) \ - do { errno = (errcode); } while (0) -#endif - -/* - * Manipulation functions for struct timeval - */ -#ifdef _EVENT_HAVE_TIMERADD -#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp)) -#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp)) -#else -#define evutil_timeradd(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ - if ((vvp)->tv_usec >= 1000000) { \ - (vvp)->tv_sec++; \ - (vvp)->tv_usec -= 1000000; \ - } \ - } while (0) -#define evutil_timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) -#endif /* !_EVENT_HAVE_HAVE_TIMERADD */ - -#ifdef _EVENT_HAVE_TIMERCLEAR -#define evutil_timerclear(tvp) timerclear(tvp) -#else -#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#endif - -#ifdef _EVENT_HAVE_TIMERCMP -#define evutil_timercmp(tvp, uvp, cmp) timercmp((tvp), (uvp), cmp) -#else -#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)) -#endif - -#ifdef _EVENT_HAVE_TIMERISSET -#define evutil_timerisset(tvp) timerisset(tvp) -#else -#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#endif - - -/* big-int related functions */ -ev_int64_t evutil_strtoll(const char *s, char **endptr, int base); - -#ifdef __cplusplus -} -#endif - -#endif /* _EVUTIL_H_ */ diff --git a/extra/libevent/http-internal.h b/extra/libevent/http-internal.h deleted file mode 100644 index e9a45f124d8..00000000000 --- a/extra/libevent/http-internal.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 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_CONNECTED /* connection is established */ -}; - -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 */ - - 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); - -struct evhttp { - struct event bind_ev; - - 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_lines(struct evhttp_request *, struct evbuffer*); - -void evhttp_start_read(struct evhttp_connection *); -void evhttp_read_header(int, short, void *); -void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *); - -void evhttp_write_buffer(struct evhttp_connection *, - void (*)(struct evhttp_connection *, void *), void *); - -/* response sending HTML the data in the buffer */ -void evhttp_response_code(struct evhttp_request *, int, const char *); -void evhttp_send_page(struct evhttp_request *, struct evbuffer *); - -#endif /* _HTTP_H */ diff --git a/extra/libevent/http.c b/extra/libevent/http.c deleted file mode 100644 index d56a34ca122..00000000000 --- a/extra/libevent/http.c +++ /dev/null @@ -1,2512 +0,0 @@ -/* - * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_SYS_IOCCOM_H -#include <sys/ioccom.h> -#endif - -#ifndef WIN32 -#include <sys/resource.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/wait.h> -#endif - -#include <sys/queue.h> - -#ifndef WIN32 -#include <netinet/in.h> -#include <netdb.h> -#endif - -#ifdef WIN32 -#include <winsock2.h> -#endif - -#include <assert.h> -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifndef WIN32 -#include <syslog.h> -#endif -#include <signal.h> -#include <time.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif - -#undef timeout_pending -#undef timeout_initialized - -#include "strlcpy-internal.h" -#include "event.h" -#include "evhttp.h" -#include "evutil.h" -#include "log.h" -#include "http-internal.h" - -#ifdef WIN32 -#define snprintf _snprintf -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#define strdup _strdup -#endif - -#ifndef HAVE_GETADDRINFO -struct addrinfo { - int ai_family; - int ai_socktype; - int ai_protocol; - size_t ai_addrlen; - struct sockaddr *ai_addr; - struct addrinfo *ai_next; -}; -static int -fake_getaddrinfo(const char *hostname, struct addrinfo *ai) -{ - struct hostent *he = NULL; - struct sockaddr_in *sa; - if (hostname) { - he = gethostbyname(hostname); - if (!he) - return (-1); - } - ai->ai_family = he ? he->h_addrtype : AF_INET; - ai->ai_socktype = SOCK_STREAM; - ai->ai_protocol = 0; - ai->ai_addrlen = sizeof(struct sockaddr_in); - if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen))) - return (-1); - sa = (struct sockaddr_in*)ai->ai_addr; - memset(sa, 0, ai->ai_addrlen); - if (he) { - sa->sin_family = he->h_addrtype; - memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length); - } else { - sa->sin_family = AF_INET; - sa->sin_addr.s_addr = INADDR_ANY; - } - ai->ai_next = NULL; - return (0); -} -static void -fake_freeaddrinfo(struct addrinfo *ai) -{ - free(ai->ai_addr); -} -#endif - -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -/* wrapper for setting the base from the http server */ -#define EVHTTP_BASE_SET(x, y) do { \ - if ((x)->base != NULL) event_base_set((x)->base, y); \ -} while (0) - -extern int debug; - -static int socket_connect(int fd, const char *address, unsigned short port); -static int bind_socket_ai(struct addrinfo *); -static int bind_socket(const char *, u_short); -static void name_from_addr(struct sockaddr *, socklen_t, char **, char **); -static int evhttp_associate_new_request_with_connection( - struct evhttp_connection *evcon); -static void evhttp_connection_start_detectclose( - struct evhttp_connection *evcon); -static void evhttp_connection_stop_detectclose( - struct evhttp_connection *evcon); -static void evhttp_request_dispatch(struct evhttp_connection* evcon); - -void evhttp_read(int, short, void *); -void evhttp_write(int, short, void *); - -#ifndef HAVE_STRSEP -/* strsep replacement for platforms that lack it. Only works if - * del is one character long. */ -static char * -strsep(char **s, const char *del) -{ - char *d, *tok; - assert(strlen(del) == 1); - if (!s || !*s) - return NULL; - tok = *s; - d = strstr(tok, del); - if (d) { - *d = '\0'; - *s = d + 1; - } else - *s = NULL; - return tok; -} -#endif - -static const char * -html_replace(char ch, char *buf) -{ - switch (ch) { - case '<': - return "<"; - case '>': - return ">"; - case '"': - return """; - case '\'': - return "'"; - case '&': - return "&"; - default: - break; - } - - /* Echo the character back */ - buf[0] = ch; - buf[1] = '\0'; - - return buf; -} - -/* - * Replaces <, >, ", ' and & with <, >, ", - * ' and & correspondingly. - * - * The returned string needs to be freed by the caller. - */ - -char * -evhttp_htmlescape(const char *html) -{ - int i, new_size = 0, old_size = strlen(html); - char *escaped_html, *p; - char scratch_space[2]; - - for (i = 0; i < old_size; ++i) - new_size += strlen(html_replace(html[i], scratch_space)); - - p = escaped_html = malloc(new_size + 1); - if (escaped_html == NULL) - event_err(1, "%s: malloc(%d)", __func__, new_size + 1); - for (i = 0; i < old_size; ++i) { - const char *replaced = html_replace(html[i], scratch_space); - /* this is length checked */ - strcpy(p, replaced); - p += strlen(replaced); - } - - *p = '\0'; - - return (escaped_html); -} - -static const char * -evhttp_method(enum evhttp_cmd_type type) -{ - const char *method; - - switch (type) { - case EVHTTP_REQ_GET: - method = "GET"; - break; - case EVHTTP_REQ_POST: - method = "POST"; - break; - case EVHTTP_REQ_HEAD: - method = "HEAD"; - break; - default: - method = NULL; - break; - } - - return (method); -} - -static void -evhttp_add_event(struct event *ev, int timeout, int default_timeout) -{ - if (timeout != 0) { - struct timeval tv; - - evutil_timerclear(&tv); - tv.tv_sec = timeout != -1 ? timeout : default_timeout; - event_add(ev, &tv); - } else { - event_add(ev, NULL); - } -} - -void -evhttp_write_buffer(struct evhttp_connection *evcon, - void (*cb)(struct evhttp_connection *, void *), void *arg) -{ - event_debug(("%s: preparing to write buffer\n", __func__)); - - /* Set call back */ - evcon->cb = cb; - evcon->cb_arg = arg; - - /* check if the event is already pending */ - if (event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) - event_del(&evcon->ev); - - event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon); - EVHTTP_BASE_SET(evcon, &evcon->ev); - evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT); -} - -/* - * Create the headers need for an HTTP request - */ -static void -evhttp_make_header_request(struct evhttp_connection *evcon, - struct evhttp_request *req) -{ - char line[1024]; - const char *method; - - evhttp_remove_header(req->output_headers, "Accept-Encoding"); - evhttp_remove_header(req->output_headers, "Proxy-Connection"); - - /* Generate request line */ - method = evhttp_method(req->type); - snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n", - method, req->uri, req->major, req->minor); - evbuffer_add(evcon->output_buffer, line, strlen(line)); - - /* Add the content length on a post request if missing */ - if (req->type == EVHTTP_REQ_POST && - evhttp_find_header(req->output_headers, "Content-Length") == NULL){ - char size[12]; - snprintf(size, sizeof(size), "%ld", - (long)EVBUFFER_LENGTH(req->output_buffer)); - evhttp_add_header(req->output_headers, "Content-Length", size); - } -} - -static int -evhttp_is_connection_close(int flags, struct evkeyvalq* headers) -{ - if (flags & EVHTTP_PROXY_REQUEST) { - /* proxy connection */ - const char *connection = evhttp_find_header(headers, "Proxy-Connection"); - return (connection == NULL || strcasecmp(connection, "keep-alive") != 0); - } else { - const char *connection = evhttp_find_header(headers, "Connection"); - return (connection != NULL && strcasecmp(connection, "close") == 0); - } -} - -static int -evhttp_is_connection_keepalive(struct evkeyvalq* headers) -{ - const char *connection = evhttp_find_header(headers, "Connection"); - return (connection != NULL - && strncasecmp(connection, "keep-alive", 10) == 0); -} - -static void -evhttp_maybe_add_date_header(struct evkeyvalq *headers) -{ - if (evhttp_find_header(headers, "Date") == NULL) { - char date[50]; -#ifndef WIN32 - struct tm cur; -#endif - struct tm *cur_p; - time_t t = time(NULL); -#ifdef WIN32 - cur_p = gmtime(&t); -#else - gmtime_r(&t, &cur); - cur_p = &cur; -#endif - if (strftime(date, sizeof(date), - "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) { - evhttp_add_header(headers, "Date", date); - } - } -} - -static void -evhttp_maybe_add_content_length_header(struct evkeyvalq *headers, - long content_length) -{ - if (evhttp_find_header(headers, "Transfer-Encoding") == NULL && - evhttp_find_header(headers, "Content-Length") == NULL) { - char len[12]; - snprintf(len, sizeof(len), "%ld", content_length); - evhttp_add_header(headers, "Content-Length", len); - } -} - -/* - * Create the headers needed for an HTTP reply - */ - -static void -evhttp_make_header_response(struct evhttp_connection *evcon, - struct evhttp_request *req) -{ - char line[1024]; - snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n", - req->major, req->minor, req->response_code, - req->response_code_line); - evbuffer_add(evcon->output_buffer, line, strlen(line)); - - if (req->major == 1 && req->minor == 1) - evhttp_maybe_add_date_header(req->output_headers); - - if (req->major == 1 && - (req->minor == 1 || - evhttp_is_connection_keepalive(req->input_headers))) { - /* - * we need to add the content length if the user did - * not give it, this is required for persistent - * connections to work. - */ - evhttp_maybe_add_content_length_header(req->output_headers, - (long)EVBUFFER_LENGTH(req->output_buffer)); - } - - /* Potentially add headers for unidentified content. */ - if (EVBUFFER_LENGTH(req->output_buffer)) { - if (evhttp_find_header(req->output_headers, - "Content-Type") == NULL) { - evhttp_add_header(req->output_headers, - "Content-Type", "text/html; charset=ISO-8859-1"); - } - } - - /* if the request asked for a close, we send a close, too */ - if (evhttp_is_connection_close(req->flags, req->input_headers)) { - evhttp_remove_header(req->output_headers, "Connection"); - if (!(req->flags & EVHTTP_PROXY_REQUEST)) - evhttp_add_header(req->output_headers, "Connection", "close"); - evhttp_remove_header(req->output_headers, "Proxy-Connection"); - } -} - -void -evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) -{ - char line[1024]; - struct evkeyval *header; - - /* - * Depending if this is a HTTP request or response, we might need to - * add some new headers or remove existing headers. - */ - if (req->kind == EVHTTP_REQUEST) { - evhttp_make_header_request(evcon, req); - } else { - evhttp_make_header_response(evcon, req); - } - - TAILQ_FOREACH(header, req->output_headers, next) { - snprintf(line, sizeof(line), "%s: %s\r\n", - header->key, header->value); - evbuffer_add(evcon->output_buffer, line, strlen(line)); - } - evbuffer_add(evcon->output_buffer, "\r\n", 2); - - if (EVBUFFER_LENGTH(req->output_buffer) > 0) { - /* - * For a request, we add the POST data, for a reply, this - * is the regular data. - */ - evbuffer_add_buffer(evcon->output_buffer, req->output_buffer); - } -} - -/* Separated host, port and file from URI */ - -int -evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile) -{ - /* XXX not threadsafe. */ - static char host[1024]; - static char file[1024]; - char *p; - const char *p2; - int len; - u_short port; - - len = strlen(HTTP_PREFIX); - if (strncasecmp(url, HTTP_PREFIX, len)) - return (-1); - - url += len; - - /* We might overrun */ - if (strlcpy(host, url, sizeof (host)) >= sizeof(host)) - return (-1); - - p = strchr(host, '/'); - if (p != NULL) { - *p = '\0'; - p2 = p + 1; - } else - p2 = NULL; - - if (pfile != NULL) { - /* Generate request file */ - if (p2 == NULL) - p2 = ""; - snprintf(file, sizeof(file), "/%s", p2); - } - - p = strchr(host, ':'); - if (p != NULL) { - *p = '\0'; - port = atoi(p + 1); - - if (port == 0) - return (-1); - } else - port = HTTP_DEFAULTPORT; - - if (phost != NULL) - *phost = host; - if (pport != NULL) - *pport = port; - if (pfile != NULL) - *pfile = file; - - return (0); -} - -static int -evhttp_connection_incoming_fail(struct evhttp_request *req, - enum evhttp_connection_error error) -{ - switch (error) { - case EVCON_HTTP_TIMEOUT: - case EVCON_HTTP_EOF: - /* - * these are cases in which we probably should just - * close the connection and not send a reply. this - * case may happen when a browser keeps a persistent - * connection open and we timeout on the read. - */ - return (-1); - case EVCON_HTTP_INVALID_HEADER: - default: /* xxx: probably should just error on default */ - /* the callback looks at the uri to determine errors */ - if (req->uri) { - free(req->uri); - req->uri = NULL; - } - - /* - * the callback needs to send a reply, once the reply has - * been send, the connection should get freed. - */ - (*req->cb)(req, req->cb_arg); - } - - return (0); -} - -void -evhttp_connection_fail(struct evhttp_connection *evcon, - enum evhttp_connection_error error) -{ - struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); - void (*cb)(struct evhttp_request *, void *); - void *cb_arg; - assert(req != NULL); - - if (evcon->flags & EVHTTP_CON_INCOMING) { - /* - * for incoming requests, there are two different - * failure cases. it's either a network level error - * or an http layer error. for problems on the network - * layer like timeouts we just drop the connections. - * For HTTP problems, we might have to send back a - * reply before the connection can be freed. - */ - if (evhttp_connection_incoming_fail(req, error) == -1) - evhttp_connection_free(evcon); - return; - } - - /* save the callback for later; the cb might free our object */ - cb = req->cb; - cb_arg = req->cb_arg; - - TAILQ_REMOVE(&evcon->requests, req, next); - evhttp_request_free(req); - - /* xxx: maybe we should fail all requests??? */ - - /* reset the connection */ - evhttp_connection_reset(evcon); - - /* We are trying the next request that was queued on us */ - if (TAILQ_FIRST(&evcon->requests) != NULL) - evhttp_connection_connect(evcon); - - /* inform the user */ - if (cb != NULL) - (*cb)(NULL, cb_arg); -} - -void -evhttp_write(int fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - int n; - - if (what == EV_TIMEOUT) { - evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); - return; - } - - n = evbuffer_write(evcon->output_buffer, fd); - if (n == -1) { - event_debug(("%s: evbuffer_write", __func__)); - evhttp_connection_fail(evcon, EVCON_HTTP_EOF); - return; - } - - if (n == 0) { - event_debug(("%s: write nothing", __func__)); - evhttp_connection_fail(evcon, EVCON_HTTP_EOF); - return; - } - - if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) { - evhttp_add_event(&evcon->ev, - evcon->timeout, HTTP_WRITE_TIMEOUT); - return; - } - - /* Activate our call back */ - if (evcon->cb != NULL) - (*evcon->cb)(evcon, evcon->cb_arg); -} - -static void -evhttp_connection_done(struct evhttp_connection *evcon) -{ - struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); - int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING; - - /* - * if this is an incoming connection, we need to leave the request - * on the connection, so that we can reply to it. - */ - if (con_outgoing) { - int need_close; - TAILQ_REMOVE(&evcon->requests, req, next); - req->evcon = NULL; - - need_close = - evhttp_is_connection_close(req->flags, req->input_headers) || - evhttp_is_connection_close(req->flags, req->output_headers); - - /* check if we got asked to close the connection */ - if (need_close) - evhttp_connection_reset(evcon); - - if (TAILQ_FIRST(&evcon->requests) != NULL) { - /* - * We have more requests; reset the connection - * and deal with the next request. xxx: no - * persistent connection right now - */ - if (evcon->state != EVCON_CONNECTED) - evhttp_connection_connect(evcon); - else - evhttp_request_dispatch(evcon); - } else if (!need_close) { - /* - * The connection is going to be persistent, but we - * need to detect if the other side closes it. - */ - evhttp_connection_start_detectclose(evcon); - } - } - - /* notify the user of the request */ - (*req->cb)(req, req->cb_arg); - - /* if this was an outgoing request, we own and it's done. so free it */ - if (con_outgoing) { - evhttp_request_free(req); - } -} - -/* - * Handles reading from a chunked request. - * return 1: all data has been read - * return 0: more data is expected - * return -1: data is corrupted - */ - -static int -evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) -{ - int len; - - while ((len = EVBUFFER_LENGTH(buf)) > 0) { - if (req->ntoread < 0) { - /* Read chunk size */ - char *p = evbuffer_readline(buf); - char *endp; - int error; - if (p == NULL) - break; - /* the last chunk is on a new line? */ - if (strlen(p) == 0) { - free(p); - continue; - } - req->ntoread = evutil_strtoll(p, &endp, 16); - error = *p == '\0' || (*endp != '\0' && *endp != ' '); - free(p); - if (error) { - /* could not get chunk size */ - return (-1); - } - if (req->ntoread == 0) { - /* Last chunk */ - return (1); - } - continue; - } - - /* don't have enough to complete a chunk; wait for more */ - if (len < req->ntoread) - return (0); - - /* Completed chunk */ - evbuffer_add(req->input_buffer, - EVBUFFER_DATA(buf), req->ntoread); - evbuffer_drain(buf, req->ntoread); - req->ntoread = -1; - if (req->chunk_cb != NULL) { - (*req->chunk_cb)(req, req->cb_arg); - evbuffer_drain(req->input_buffer, - EVBUFFER_LENGTH(req->input_buffer)); - } - } - - return (0); -} - -static void -evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) -{ - struct evbuffer *buf = evcon->input_buffer; - - if (req->chunked) { - int res = evhttp_handle_chunked_read(req, buf); - if (res == 1) { - /* finished last chunk */ - evhttp_connection_done(evcon); - return; - } else if (res == -1) { - /* corrupted data */ - evhttp_connection_fail(evcon, - EVCON_HTTP_INVALID_HEADER); - return; - } - } else if (req->ntoread < 0) { - /* Read until connection close. */ - evbuffer_add_buffer(req->input_buffer, buf); - } else if (EVBUFFER_LENGTH(buf) >= req->ntoread) { - /* Completed content length */ - evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf), - req->ntoread); - evbuffer_drain(buf, req->ntoread); - req->ntoread = 0; - evhttp_connection_done(evcon); - return; - } - /* Read more! */ - event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon); - EVHTTP_BASE_SET(evcon, &evcon->ev); - evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT); -} - -/* - * Reads data into a buffer structure until no more data - * can be read on the file descriptor or we have read all - * the data that we wanted to read. - * Execute callback when done. - */ - -void -evhttp_read(int fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); - struct evbuffer *buf = evcon->input_buffer; - int n, len; - - if (what == EV_TIMEOUT) { - evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); - return; - } - n = evbuffer_read(buf, fd, -1); - len = EVBUFFER_LENGTH(buf); - event_debug(("%s: got %d on %d\n", __func__, n, fd)); - - if (n == -1) { - event_debug(("%s: evbuffer_read", __func__)); - evhttp_connection_fail(evcon, EVCON_HTTP_EOF); - return; - } else if (n == 0) { - /* Connection closed */ - evhttp_connection_done(evcon); - return; - } - evhttp_read_body(evcon, req); -} - -static void -evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg) -{ - /* This is after writing the request to the server */ - struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); - assert(req != NULL); - - /* We are done writing our header and are now expecting the response */ - req->kind = EVHTTP_RESPONSE; - - evhttp_start_read(evcon); -} - -/* - * Clean up a connection object - */ - -void -evhttp_connection_free(struct evhttp_connection *evcon) -{ - struct evhttp_request *req; - - /* notify interested parties that this connection is going down */ - if (evcon->fd != -1) { - if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL) - (*evcon->closecb)(evcon, evcon->closecb_arg); - } - - /* remove all requests that might be queued on this connection */ - while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { - TAILQ_REMOVE(&evcon->requests, req, next); - evhttp_request_free(req); - } - - if (evcon->http_server != NULL) { - struct evhttp *http = evcon->http_server; - TAILQ_REMOVE(&http->connections, evcon, next); - } - - if (event_initialized(&evcon->close_ev)) - event_del(&evcon->close_ev); - - if (event_initialized(&evcon->ev)) - event_del(&evcon->ev); - - if (evcon->fd != -1) - EVUTIL_CLOSESOCKET(evcon->fd); - - if (evcon->bind_address != NULL) - free(evcon->bind_address); - - if (evcon->address != NULL) - free(evcon->address); - - if (evcon->input_buffer != NULL) - evbuffer_free(evcon->input_buffer); - - if (evcon->output_buffer != NULL) - evbuffer_free(evcon->output_buffer); - - free(evcon); -} - -void -evhttp_connection_set_local_address(struct evhttp_connection *evcon, - const char *address) -{ - assert(evcon->state == EVCON_DISCONNECTED); - if (evcon->bind_address) - free(evcon->bind_address); - if ((evcon->bind_address = strdup(address)) == NULL) - event_err(1, "%s: strdup", __func__); -} - - -static void -evhttp_request_dispatch(struct evhttp_connection* evcon) -{ - struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); - - /* this should not usually happy but it's possible */ - if (req == NULL) - return; - - /* delete possible close detection events */ - evhttp_connection_stop_detectclose(evcon); - - /* we assume that the connection is connected already */ - assert(evcon->state == EVCON_CONNECTED); - - /* Create the header from the store arguments */ - evhttp_make_header(evcon, req); - - evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); -} - -/* Reset our connection state */ -void -evhttp_connection_reset(struct evhttp_connection *evcon) -{ - if (event_initialized(&evcon->ev)) - event_del(&evcon->ev); - - if (evcon->fd != -1) { - /* inform interested parties about connection close */ - if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL) - (*evcon->closecb)(evcon, evcon->closecb_arg); - - EVUTIL_CLOSESOCKET(evcon->fd); - evcon->fd = -1; - } - evcon->state = EVCON_DISCONNECTED; - - /* remove unneeded flags */ - evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; -} - -static void -evhttp_detect_close_cb(int fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - evhttp_connection_reset(evcon); -} - -static void -evhttp_connection_start_detectclose(struct evhttp_connection *evcon) -{ - evcon->flags |= EVHTTP_CON_CLOSEDETECT; - - if (event_initialized(&evcon->close_ev)) - event_del(&evcon->close_ev); - event_set(&evcon->close_ev, evcon->fd, EV_READ, - evhttp_detect_close_cb, evcon); - EVHTTP_BASE_SET(evcon, &evcon->close_ev); - event_add(&evcon->close_ev, NULL); -} - -static void -evhttp_connection_stop_detectclose(struct evhttp_connection *evcon) -{ - evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; - event_del(&evcon->close_ev); -} - -static void -evhttp_connection_retry(int fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - - evcon->state = EVCON_DISCONNECTED; - evhttp_connection_connect(evcon); -} - -/* - * Call back for asynchronous connection attempt. - */ - -static void -evhttp_connectioncb(int fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - int error; - socklen_t errsz = sizeof(error); - - if (what == EV_TIMEOUT) { - event_debug(("%s: connection timeout for \"%s:%d\" on %d", - __func__, evcon->address, evcon->port, evcon->fd)); - goto cleanup; - } - - /* Check if the connection completed */ - if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, - &errsz) == -1) { - event_debug(("%s: getsockopt for \"%s:%d\" on %d", - __func__, evcon->address, evcon->port, evcon->fd)); - goto cleanup; - } - - if (error) { - event_debug(("%s: connect failed for \"%s:%d\" on %d: %s", - __func__, evcon->address, evcon->port, evcon->fd, - strerror(error))); - goto cleanup; - } - - /* We are connected to the server now */ - event_debug(("%s: connected to \"%s:%d\" on %d\n", - __func__, evcon->address, evcon->port, evcon->fd)); - - /* Reset the retry count as we were successful in connecting */ - evcon->retry_cnt = 0; - evcon->state = EVCON_CONNECTED; - - /* try to start requests that have queued up on this connection */ - evhttp_request_dispatch(evcon); - return; - - cleanup: - if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { - evtimer_set(&evcon->ev, evhttp_connection_retry, evcon); - EVHTTP_BASE_SET(evcon, &evcon->ev); - evhttp_add_event(&evcon->ev, MIN(3600, 2 << evcon->retry_cnt), - HTTP_CONNECT_TIMEOUT); - evcon->retry_cnt++; - return; - } - evhttp_connection_reset(evcon); - - /* for now, we just signal all requests by executing their callbacks */ - while (TAILQ_FIRST(&evcon->requests) != NULL) { - struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); - TAILQ_REMOVE(&evcon->requests, request, next); - request->evcon = NULL; - - /* we might want to set an error here */ - request->cb(request, request->cb_arg); - evhttp_request_free(request); - } -} - -/* - * Check if we got a valid response code. - */ - -static int -evhttp_valid_response_code(int code) -{ - if (code == 0) - return (0); - - return (1); -} - -/* Parses the status line of a web server */ - -static int -evhttp_parse_response_line(struct evhttp_request *req, char *line) -{ - char *protocol; - char *number; - char *readable; - - protocol = strsep(&line, " "); - if (line == NULL) - return (-1); - number = strsep(&line, " "); - if (line == NULL) - return (-1); - readable = line; - - if (strcmp(protocol, "HTTP/1.0") == 0) { - req->major = 1; - req->minor = 0; - } else if (strcmp(protocol, "HTTP/1.1") == 0) { - req->major = 1; - req->minor = 1; - } else { - event_debug(("%s: bad protocol \"%s\"", - __func__, protocol)); - return (-1); - } - - req->response_code = atoi(number); - if (!evhttp_valid_response_code(req->response_code)) { - event_debug(("%s: bad response code \"%s\"", - __func__, number)); - return (-1); - } - - if ((req->response_code_line = strdup(readable)) == NULL) - event_err(1, "%s: strdup", __func__); - - return (0); -} - -/* Parse the first line of a HTTP request */ - -static int -evhttp_parse_request_line(struct evhttp_request *req, char *line) -{ - char *method; - char *uri; - char *version; - - /* Parse the request line */ - method = strsep(&line, " "); - if (line == NULL) - return (-1); - uri = strsep(&line, " "); - if (line == NULL) - return (-1); - version = strsep(&line, " "); - if (line != NULL) - return (-1); - - /* First line */ - if (strcmp(method, "GET") == 0) { - req->type = EVHTTP_REQ_GET; - } else if (strcmp(method, "POST") == 0) { - req->type = EVHTTP_REQ_POST; - } else if (strcmp(method, "HEAD") == 0) { - req->type = EVHTTP_REQ_HEAD; - } else { - event_debug(("%s: bad method %s on request %p from %s", - __func__, method, req, req->remote_host)); - return (-1); - } - - if (strcmp(version, "HTTP/1.0") == 0) { - req->major = 1; - req->minor = 0; - } else if (strcmp(version, "HTTP/1.1") == 0) { - req->major = 1; - req->minor = 1; - } else { - event_debug(("%s: bad version %s on request %p from %s", - __func__, version, req, req->remote_host)); - return (-1); - } - - if ((req->uri = strdup(uri)) == NULL) { - event_debug(("%s: evhttp_decode_uri", __func__)); - return (-1); - } - - /* determine if it's a proxy request */ - if (strlen(req->uri) > 0 && req->uri[0] != '/') - req->flags |= EVHTTP_PROXY_REQUEST; - - return (0); -} - -const char * -evhttp_find_header(const struct evkeyvalq *headers, const char *key) -{ - struct evkeyval *header; - - TAILQ_FOREACH(header, headers, next) { - if (strcasecmp(header->key, key) == 0) - return (header->value); - } - - return (NULL); -} - -void -evhttp_clear_headers(struct evkeyvalq *headers) -{ - struct evkeyval *header; - - for (header = TAILQ_FIRST(headers); - header != NULL; - header = TAILQ_FIRST(headers)) { - TAILQ_REMOVE(headers, header, next); - free(header->key); - free(header->value); - free(header); - } -} - -/* - * Returns 0, if the header was successfully removed. - * Returns -1, if the header could not be found. - */ - -int -evhttp_remove_header(struct evkeyvalq *headers, const char *key) -{ - struct evkeyval *header; - - TAILQ_FOREACH(header, headers, next) { - if (strcasecmp(header->key, key) == 0) - break; - } - - if (header == NULL) - return (-1); - - /* Free and remove the header that we found */ - TAILQ_REMOVE(headers, header, next); - free(header->key); - free(header->value); - free(header); - - return (0); -} - -int -evhttp_add_header(struct evkeyvalq *headers, - const char *key, const char *value) -{ - struct evkeyval *header = NULL; - - event_debug(("%s: key: %s val: %s\n", __func__, key, value)); - - if (strchr(value, '\r') != NULL || strchr(value, '\n') != NULL || - strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) { - /* drop illegal headers */ - event_debug(("%s: dropping illegal header\n", __func__)); - return (-1); - } - - header = calloc(1, sizeof(struct evkeyval)); - if (header == NULL) { - event_warn("%s: calloc", __func__); - return (-1); - } - if ((header->key = strdup(key)) == NULL) { - free(header); - event_warn("%s: strdup", __func__); - return (-1); - } - if ((header->value = strdup(value)) == NULL) { - free(header->key); - free(header); - event_warn("%s: strdup", __func__); - return (-1); - } - - TAILQ_INSERT_TAIL(headers, header, next); - - return (0); -} - -/* - * Parses header lines from a request or a response into the specified - * request object given an event buffer. - * - * Returns - * -1 on error - * 0 when we need to read more headers - * 1 when all headers have been read. - */ - -int -evhttp_parse_lines(struct evhttp_request *req, struct evbuffer* buffer) -{ - char *line; - int done = 0; - - struct evkeyvalq* headers = req->input_headers; - while ((line = evbuffer_readline(buffer)) != NULL) { - char *skey, *svalue; - - if (*line == '\0') { /* Last header - Done */ - done = 1; - free (line); - break; - } - - /* Processing of header lines */ - if (req->got_firstline == 0) { - switch (req->kind) { - case EVHTTP_REQUEST: - if (evhttp_parse_request_line(req, line) == -1) - goto error; - break; - case EVHTTP_RESPONSE: - if (evhttp_parse_response_line(req, line) == -1) - goto error; - break; - default: - goto error; - } - req->got_firstline = 1; - } else { - /* Regular header */ - svalue = line; - skey = strsep(&svalue, ":"); - if (svalue == NULL) - goto error; - - svalue += strspn(svalue, " "); - - if (evhttp_add_header(headers, skey, svalue) == -1) - goto error; - } - - free (line); - } - - return (done); - - error: - free (line); - return (-1); -} - -static int -evhttp_get_body_length(struct evhttp_request *req) -{ - struct evkeyvalq *headers = req->input_headers; - const char *content_length; - const char *connection; - - content_length = evhttp_find_header(headers, "Content-Length"); - connection = evhttp_find_header(headers, "Connection"); - - if (content_length == NULL && connection == NULL) - req->ntoread = -1; - else if (content_length == NULL && - strcasecmp(connection, "Close") != 0) { - /* Bad combination, we don't know when it will end */ - event_warnx("%s: we got no content length, but the " - "server wants to keep the connection open: %s.", - __func__, connection); - return (-1); - } else if (content_length == NULL) { - req->ntoread = -1; - } else { - char *endp; - req->ntoread = evutil_strtoll(content_length, &endp, 10); - if (*content_length == '\0' || *endp != '\0') { - event_warnx("%s: illegal content length: %s", - __func__, content_length); - return (-1); - } - } - - event_debug(("%s: bytes to read: %d (in buffer %d)\n", - __func__, req->ntoread, - EVBUFFER_LENGTH(req->evcon->input_buffer))); - - return (0); -} - -static void -evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) -{ - const char *xfer_enc; - - /* If this is a request without a body, then we are done */ - if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) { - evhttp_connection_done(evcon); - return; - } - xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); - if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) { - req->chunked = 1; - req->ntoread = -1; - } else { - if (evhttp_get_body_length(req) == -1) { - evhttp_connection_fail(evcon, - EVCON_HTTP_INVALID_HEADER); - return; - } - } - evhttp_read_body(evcon, req); -} - -void -evhttp_read_header(int fd, short what, void *arg) -{ - struct evhttp_connection *evcon = arg; - struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); - int n, res; - - if (what == EV_TIMEOUT) { - event_debug(("%s: timeout on %d\n", __func__, fd)); - evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); - return; - } - - n = evbuffer_read(evcon->input_buffer, fd, -1); - if (n == 0) { - event_debug(("%s: no more data on %d", __func__, fd)); - evhttp_connection_fail(evcon, EVCON_HTTP_EOF); - return; - } - if (n == -1) { - event_debug(("%s: bad read on %d", __func__, fd)); - evhttp_connection_fail(evcon, EVCON_HTTP_EOF); - return; - } - - res = evhttp_parse_lines(req, evcon->input_buffer); - if (res == -1) { - /* Error while reading, terminate */ - event_debug(("%s: bad header lines on %d\n", __func__, fd)); - evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); - return; - } else if (res == 0) { - /* Need more header lines */ - evhttp_add_event(&evcon->ev, - evcon->timeout, HTTP_READ_TIMEOUT); - return; - } - - /* Done reading headers, do the real work */ - switch (req->kind) { - case EVHTTP_REQUEST: - event_debug(("%s: checking for post data on %d\n", - __func__, fd)); - evhttp_get_body(evcon, req); - break; - - case EVHTTP_RESPONSE: - if (req->response_code == HTTP_NOCONTENT || - req->response_code == HTTP_NOTMODIFIED || - (req->response_code >= 100 && req->response_code < 200)) { - event_debug(("%s: skipping body for code %d\n", - __func__, req->response_code)); - evhttp_connection_done(evcon); - } else { - event_debug(("%s: start of read body for %s on %d\n", - __func__, req->remote_host, fd)); - evhttp_get_body(evcon, req); - } - break; - - default: - event_warnx("%s: bad header on %d", __func__, fd); - evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); - break; - } -} - -/* - * Creates a TCP connection to the specified port and executes a callback - * when finished. Failure or sucess is indicate by the passed connection - * object. - * - * Although this interface accepts a hostname, it is intended to take - * only numeric hostnames so that non-blocking DNS resolution can - * happen elsewhere. - */ - -struct evhttp_connection * -evhttp_connection_new(const char *address, unsigned short port) -{ - struct evhttp_connection *evcon = NULL; - - event_debug(("Attempting connection to %s:%d\n", address, port)); - - if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) { - event_warn("%s: calloc failed", __func__); - goto error; - } - - evcon->fd = -1; - evcon->port = port; - - evcon->timeout = -1; - evcon->retry_cnt = evcon->retry_max = 0; - - if ((evcon->address = strdup(address)) == NULL) { - event_warn("%s: strdup failed", __func__); - goto error; - } - - if ((evcon->input_buffer = evbuffer_new()) == NULL) { - event_warn("%s: evbuffer_new failed", __func__); - goto error; - } - - if ((evcon->output_buffer = evbuffer_new()) == NULL) { - event_warn("%s: evbuffer_new failed", __func__); - goto error; - } - - evcon->state = EVCON_DISCONNECTED; - TAILQ_INIT(&evcon->requests); - - return (evcon); - - error: - if (evcon != NULL) - evhttp_connection_free(evcon); - return (NULL); -} - -void evhttp_connection_set_base(struct evhttp_connection *evcon, - struct event_base *base) -{ - assert(evcon->base == NULL); - assert(evcon->state == EVCON_DISCONNECTED); - evcon->base = base; -} - -void -evhttp_connection_set_timeout(struct evhttp_connection *evcon, - int timeout_in_secs) -{ - evcon->timeout = timeout_in_secs; -} - -void -evhttp_connection_set_retries(struct evhttp_connection *evcon, - int retry_max) -{ - evcon->retry_max = retry_max; -} - -void -evhttp_connection_set_closecb(struct evhttp_connection *evcon, - void (*cb)(struct evhttp_connection *, void *), void *cbarg) -{ - evcon->closecb = cb; - evcon->closecb_arg = cbarg; -} - -void -evhttp_connection_get_peer(struct evhttp_connection *evcon, - char **address, u_short *port) -{ - *address = evcon->address; - *port = evcon->port; -} - -int -evhttp_connection_connect(struct evhttp_connection *evcon) -{ - if (evcon->state == EVCON_CONNECTING) - return (0); - - evhttp_connection_reset(evcon); - - assert(!(evcon->flags & EVHTTP_CON_INCOMING)); - evcon->flags |= EVHTTP_CON_OUTGOING; - - evcon->fd = bind_socket(evcon->bind_address, 0); - if (evcon->fd == -1) { - event_debug(("%s: failed to bind to \"%s\"", - __func__, evcon->bind_address)); - return (-1); - } - - if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) { - EVUTIL_CLOSESOCKET(evcon->fd); evcon->fd = -1; - return (-1); - } - - /* Set up a callback for successful connection setup */ - event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon); - EVHTTP_BASE_SET(evcon, &evcon->ev); - evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_CONNECT_TIMEOUT); - - evcon->state = EVCON_CONNECTING; - - return (0); -} - -/* - * Starts an HTTP request on the provided evhttp_connection object. - * If the connection object is not connected to the web server already, - * this will start the connection. - */ - -int -evhttp_make_request(struct evhttp_connection *evcon, - struct evhttp_request *req, - enum evhttp_cmd_type type, const char *uri) -{ - /* We are making a request */ - req->kind = EVHTTP_REQUEST; - req->type = type; - if (req->uri != NULL) - free(req->uri); - if ((req->uri = strdup(uri)) == NULL) - event_err(1, "%s: strdup", __func__); - - /* Set the protocol version if it is not supplied */ - if (!req->major && !req->minor) { - req->major = 1; - req->minor = 1; - } - - assert(req->evcon == NULL); - req->evcon = evcon; - assert(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); - - TAILQ_INSERT_TAIL(&evcon->requests, req, next); - - /* If the connection object is not connected; make it so */ - if (evcon->state != EVCON_CONNECTED) - return (evhttp_connection_connect(evcon)); - - /* - * If it's connected already and we are the first in the queue, - * then we can dispatch this request immediately. Otherwise, it - * will be dispatched once the pending requests are completed. - */ - if (TAILQ_FIRST(&evcon->requests) == req) - evhttp_request_dispatch(evcon); - - return (0); -} - -/* - * Reads data from file descriptor into request structure - * Request structure needs to be set up correctly. - */ - -void -evhttp_start_read(struct evhttp_connection *evcon) -{ - /* Set up an event to read the headers */ - if (event_initialized(&evcon->ev)) - event_del(&evcon->ev); - event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read_header, evcon); - EVHTTP_BASE_SET(evcon, &evcon->ev); - - evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT); -} - -static void -evhttp_send_done(struct evhttp_connection *evcon, void *arg) -{ - int need_close; - struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); - TAILQ_REMOVE(&evcon->requests, req, next); - - /* delete possible close detection events */ - evhttp_connection_stop_detectclose(evcon); - - need_close = - (req->minor == 0 && - !evhttp_is_connection_keepalive(req->input_headers))|| - evhttp_is_connection_close(req->flags, req->input_headers) || - evhttp_is_connection_close(req->flags, req->output_headers); - - assert(req->flags & EVHTTP_REQ_OWN_CONNECTION); - evhttp_request_free(req); - - if (need_close) { - evhttp_connection_free(evcon); - return; - } - - /* we have a persistent connection; try to accept another request. */ - if (evhttp_associate_new_request_with_connection(evcon) == -1) - evhttp_connection_free(evcon); -} - -/* - * Returns an error page. - */ - -void -evhttp_send_error(struct evhttp_request *req, int error, const char *reason) -{ -#define ERR_FORMAT "<HTML><HEAD>\n" \ - "<TITLE>%d %s</TITLE>\n" \ - "</HEAD><BODY>\n" \ - "<H1>Method Not Implemented</H1>\n" \ - "Invalid method in request<P>\n" \ - "</BODY></HTML>\n" - - struct evbuffer *buf = evbuffer_new(); - - /* close the connection on error */ - evhttp_add_header(req->output_headers, "Connection", "close"); - - evhttp_response_code(req, error, reason); - - evbuffer_add_printf(buf, ERR_FORMAT, error, reason); - - evhttp_send_page(req, buf); - - evbuffer_free(buf); -#undef ERR_FORMAT -} - -/* Requires that headers and response code are already set up */ - -static inline void -evhttp_send(struct evhttp_request *req, struct evbuffer *databuf) -{ - struct evhttp_connection *evcon = req->evcon; - - assert(TAILQ_FIRST(&evcon->requests) == req); - - /* xxx: not sure if we really should expose the data buffer this way */ - if (databuf != NULL) - evbuffer_add_buffer(req->output_buffer, databuf); - - /* Adds headers to the response */ - evhttp_make_header(evcon, req); - - evhttp_write_buffer(evcon, evhttp_send_done, NULL); -} - -void -evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, - struct evbuffer *databuf) -{ - /* set up to watch for client close */ - evhttp_connection_start_detectclose(req->evcon); - evhttp_response_code(req, code, reason); - - evhttp_send(req, databuf); -} - -void -evhttp_send_reply_start(struct evhttp_request *req, int code, - const char *reason) -{ - /* set up to watch for client close */ - evhttp_connection_start_detectclose(req->evcon); - evhttp_response_code(req, code, reason); - if (req->major == 1 && req->minor == 1) { - /* use chunked encoding for HTTP/1.1 */ - evhttp_add_header(req->output_headers, "Transfer-Encoding", - "chunked"); - req->chunked = 1; - } - evhttp_make_header(req->evcon, req); - evhttp_write_buffer(req->evcon, NULL, NULL); -} - -void -evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf) -{ - if (req->chunked) { - evbuffer_add_printf(req->evcon->output_buffer, "%x\r\n", - (unsigned)EVBUFFER_LENGTH(databuf)); - } - evbuffer_add_buffer(req->evcon->output_buffer, databuf); - if (req->chunked) { - evbuffer_add(req->evcon->output_buffer, "\r\n", 2); - } - evhttp_write_buffer(req->evcon, NULL, NULL); -} - -void -evhttp_send_reply_end(struct evhttp_request *req) -{ - struct evhttp_connection *evcon = req->evcon; - - if (req->chunked) { - evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5); - evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); - req->chunked = 0; - } else if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) { - /* let the connection know that we are done with the request */ - evhttp_send_done(evcon, NULL); - } else { - /* make the callback execute after all data has been written */ - evcon->cb = evhttp_send_done; - evcon->cb_arg = NULL; - } -} - -void -evhttp_response_code(struct evhttp_request *req, int code, const char *reason) -{ - req->kind = EVHTTP_RESPONSE; - req->response_code = code; - if (req->response_code_line != NULL) - free(req->response_code_line); - req->response_code_line = strdup(reason); -} - -void -evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf) -{ - if (!req->major || !req->minor) { - req->major = 1; - req->minor = 1; - } - - if (req->kind != EVHTTP_RESPONSE) - evhttp_response_code(req, 200, "OK"); - - evhttp_clear_headers(req->output_headers); - evhttp_add_header(req->output_headers, "Content-Type", "text/html"); - evhttp_add_header(req->output_headers, "Connection", "close"); - - evhttp_send(req, databuf); -} - -static const char uri_chars[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, - /* 64 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, - /* 128 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 192 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -/* - * Helper functions to encode/decode a URI. - * The returned string must be freed by the caller. - */ -char * -evhttp_encode_uri(const char *uri) -{ - struct evbuffer *buf = evbuffer_new(); - char *p; - - for (p = (char *)uri; *p != '\0'; p++) { - if (uri_chars[(u_char)(*p)]) { - evbuffer_add(buf, p, 1); - } else { - evbuffer_add_printf(buf, "%%%02X", (u_char)(*p)); - } - } - evbuffer_add(buf, "", 1); - p = strdup((char *)EVBUFFER_DATA(buf)); - evbuffer_free(buf); - - return (p); -} - -char * -evhttp_decode_uri(const char *uri) -{ - char c, *ret; - int i, j, in_query = 0; - - ret = malloc(strlen(uri) + 1); - if (ret == NULL) - event_err(1, "%s: malloc(%lu)", __func__, - (unsigned long)(strlen(uri) + 1)); - - for (i = j = 0; uri[i] != '\0'; i++) { - c = uri[i]; - if (c == '?') { - in_query = 1; - } else if (c == '+' && in_query) { - c = ' '; - } else if (c == '%' && isxdigit((unsigned char)uri[i+1]) && - isxdigit((unsigned char)uri[i+2])) { - char tmp[] = { uri[i+1], uri[i+2], '\0' }; - c = (char)strtol(tmp, NULL, 16); - i += 2; - } - ret[j++] = c; - } - ret[j] = '\0'; - - return (ret); -} - -/* - * Helper function to parse out arguments in a query. - * The arguments are separated by key and value. - * URI should already be decoded. - */ - -void -evhttp_parse_query(const char *uri, struct evkeyvalq *headers) -{ - char *line; - char *argument; - char *p; - - TAILQ_INIT(headers); - - /* No arguments - we are done */ - if (strchr(uri, '?') == NULL) - return; - - if ((line = strdup(uri)) == NULL) - event_err(1, "%s: strdup", __func__); - - - argument = line; - - /* We already know that there has to be a ? */ - strsep(&argument, "?"); - - p = argument; - while (p != NULL && *p != '\0') { - char *key, *value; - argument = strsep(&p, "&"); - - value = argument; - key = strsep(&value, "="); - if (value == NULL) - goto error; - - value = evhttp_decode_uri(value); - event_debug(("Query Param: %s -> %s\n", key, value)); - evhttp_add_header(headers, key, value); - free(value); - } - - error: - free(line); -} - -static struct evhttp_cb * -evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req) -{ - struct evhttp_cb *cb; - size_t offset = 0; - - /* Test for different URLs */ - char *p = strchr(req->uri, '?'); - if (p != NULL) - offset = (size_t)(p - req->uri); - - TAILQ_FOREACH(cb, callbacks, next) { - int res = 0; - if (p == NULL) { - res = strcmp(cb->what, req->uri) == 0; - } else { - res = ((strncmp(cb->what, req->uri, offset) == 0) && - (cb->what[offset] == '\0')); - } - - if (res) - return (cb); - } - - return (NULL); -} - -static void -evhttp_handle_request(struct evhttp_request *req, void *arg) -{ - struct evhttp *http = arg; - struct evhttp_cb *cb = NULL; - - if (req->uri == NULL) { - evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request"); - return; - } - - if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) { - (*cb->cb)(req, cb->cbarg); - return; - } - - /* Generic call back */ - if (http->gencb) { - (*http->gencb)(req, http->gencbarg); - return; - } else { - /* We need to send a 404 here */ -#define ERR_FORMAT "<html><head>" \ - "<title>404 Not Found</title>" \ - "</head><body>" \ - "<h1>Not Found</h1>" \ - "<p>The requested URL %s was not found on this server.</p>"\ - "</body></html>\n" - - char *escaped_html = evhttp_htmlescape(req->uri); - struct evbuffer *buf = evbuffer_new(); - - evhttp_response_code(req, HTTP_NOTFOUND, "Not Found"); - - evbuffer_add_printf(buf, ERR_FORMAT, escaped_html); - - free(escaped_html); - - evhttp_send_page(req, buf); - - evbuffer_free(buf); -#undef ERR_FORMAT - } -} - -static void -accept_socket(int fd, short what, void *arg) -{ - struct evhttp *http = arg; - struct sockaddr_storage ss; - socklen_t addrlen = sizeof(ss); - int nfd; - - if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) { - event_warn("%s: bad accept", __func__); - return; - } - if (evutil_make_socket_nonblocking(nfd) < 0) - return; - - evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen); -} - -int -evhttp_bind_socket(struct evhttp *http, const char *address, u_short port) -{ - struct event *ev = &http->bind_ev; - int fd; - - if ((fd = bind_socket(address, port)) == -1) - return (-1); - - if (listen(fd, 10) == -1) { - event_warn("%s: listen", __func__); - EVUTIL_CLOSESOCKET(fd); - return (-1); - } - - /* Schedule the socket for accepting */ - event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http); - EVHTTP_BASE_SET(http, ev); - event_add(ev, NULL); - - event_debug(("Bound to port %d - Awaiting connections ... ", port)); - - return (0); -} - -static struct evhttp* -evhttp_new_object(void) -{ - struct evhttp *http = NULL; - - if ((http = calloc(1, sizeof(struct evhttp))) == NULL) { - event_warn("%s: calloc", __func__); - return (NULL); - } - - http->timeout = -1; - - TAILQ_INIT(&http->callbacks); - TAILQ_INIT(&http->connections); - - return (http); -} - -struct evhttp * -evhttp_new(struct event_base *base) -{ - struct evhttp *http = evhttp_new_object(); - - http->base = base; - - return (http); -} - -/* - * Start a web server on the specified address and port. - */ - -struct evhttp * -evhttp_start(const char *address, u_short port) -{ - struct evhttp *http = evhttp_new_object(); - - if (evhttp_bind_socket(http, address, port) == -1) { - free(http); - return (NULL); - } - - return (http); -} - -void -evhttp_free(struct evhttp* http) -{ - struct evhttp_cb *http_cb; - struct evhttp_connection *evcon; - int fd = http->bind_ev.ev_fd; - - /* Remove the accepting part */ - event_del(&http->bind_ev); - EVUTIL_CLOSESOCKET(fd); - - while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) { - /* evhttp_connection_free removes the connection */ - evhttp_connection_free(evcon); - } - - while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) { - TAILQ_REMOVE(&http->callbacks, http_cb, next); - free(http_cb->what); - free(http_cb); - } - - free(http); -} - -void -evhttp_set_timeout(struct evhttp* http, int timeout_in_secs) -{ - http->timeout = timeout_in_secs; -} - -void -evhttp_set_cb(struct evhttp *http, const char *uri, - void (*cb)(struct evhttp_request *, void *), void *cbarg) -{ - struct evhttp_cb *http_cb; - - if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL) - event_err(1, "%s: calloc", __func__); - - http_cb->what = strdup(uri); - http_cb->cb = cb; - http_cb->cbarg = cbarg; - - TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next); -} - -int -evhttp_del_cb(struct evhttp *http, const char *uri) -{ - struct evhttp_cb *http_cb; - - TAILQ_FOREACH(http_cb, &http->callbacks, next) { - if (strcmp(http_cb->what, uri) == 0) - break; - } - if (http_cb == NULL) - return (-1); - - TAILQ_REMOVE(&http->callbacks, http_cb, next); - free(http_cb->what); - free(http_cb); - - return (0); -} - -void -evhttp_set_gencb(struct evhttp *http, - void (*cb)(struct evhttp_request *, void *), void *cbarg) -{ - http->gencb = cb; - http->gencbarg = cbarg; -} - -/* - * Request related functions - */ - -struct evhttp_request * -evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg) -{ - struct evhttp_request *req = NULL; - - /* Allocate request structure */ - if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) { - event_warn("%s: calloc", __func__); - goto error; - } - - req->kind = EVHTTP_RESPONSE; - req->input_headers = calloc(1, sizeof(struct evkeyvalq)); - if (req->input_headers == NULL) { - event_warn("%s: calloc", __func__); - goto error; - } - TAILQ_INIT(req->input_headers); - - req->output_headers = calloc(1, sizeof(struct evkeyvalq)); - if (req->output_headers == NULL) { - event_warn("%s: calloc", __func__); - goto error; - } - TAILQ_INIT(req->output_headers); - - if ((req->input_buffer = evbuffer_new()) == NULL) { - event_warn("%s: evbuffer_new", __func__); - goto error; - } - - if ((req->output_buffer = evbuffer_new()) == NULL) { - event_warn("%s: evbuffer_new", __func__); - goto error; - } - - req->cb = cb; - req->cb_arg = arg; - - return (req); - - error: - if (req != NULL) - evhttp_request_free(req); - return (NULL); -} - -void -evhttp_request_free(struct evhttp_request *req) -{ - if (req->remote_host != NULL) - free(req->remote_host); - if (req->uri != NULL) - free(req->uri); - if (req->response_code_line != NULL) - free(req->response_code_line); - - evhttp_clear_headers(req->input_headers); - free(req->input_headers); - - evhttp_clear_headers(req->output_headers); - free(req->output_headers); - - if (req->input_buffer != NULL) - evbuffer_free(req->input_buffer); - - if (req->output_buffer != NULL) - evbuffer_free(req->output_buffer); - - free(req); -} - -void -evhttp_request_set_chunked_cb(struct evhttp_request *req, - void (*cb)(struct evhttp_request *, void *)) -{ - req->chunk_cb = cb; -} - -/* - * Allows for inspection of the request URI - */ - -const char * -evhttp_request_uri(struct evhttp_request *req) { - if (req->uri == NULL) - event_debug(("%s: request %p has no uri\n", req)); - return (req->uri); -} - -/* - * Takes a file descriptor to read a request from. - * The callback is executed once the whole request has been read. - */ - -static struct evhttp_connection* -evhttp_get_request_connection( - struct evhttp* http, - int fd, struct sockaddr *sa, socklen_t salen) -{ - struct evhttp_connection *evcon; - char *hostname, *portname; - - name_from_addr(sa, salen, &hostname, &portname); - event_debug(("%s: new request from %s:%s on %d\n", - __func__, hostname, portname, fd)); - - /* we need a connection object to put the http request on */ - if ((evcon = evhttp_connection_new(hostname, atoi(portname))) == NULL) - return (NULL); - - /* associate the base if we have one*/ - evhttp_connection_set_base(evcon, http->base); - - evcon->flags |= EVHTTP_CON_INCOMING; - evcon->state = EVCON_CONNECTED; - - evcon->fd = fd; - - return (evcon); -} - -static int -evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon) -{ - struct evhttp *http = evcon->http_server; - struct evhttp_request *req; - if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) - return (-1); - - req->evcon = evcon; /* the request ends up owning the connection */ - req->flags |= EVHTTP_REQ_OWN_CONNECTION; - - TAILQ_INSERT_TAIL(&evcon->requests, req, next); - - req->kind = EVHTTP_REQUEST; - - if ((req->remote_host = strdup(evcon->address)) == NULL) - event_err(1, "%s: strdup", __func__); - req->remote_port = evcon->port; - - evhttp_start_read(evcon); - - return (0); -} - -void -evhttp_get_request(struct evhttp *http, int fd, - struct sockaddr *sa, socklen_t salen) -{ - struct evhttp_connection *evcon; - - evcon = evhttp_get_request_connection(http, fd, sa, salen); - if (evcon == NULL) - return; - - /* the timeout can be used by the server to close idle connections */ - if (http->timeout != -1) - evhttp_connection_set_timeout(evcon, http->timeout); - - /* - * if we want to accept more than one request on a connection, - * we need to know which http server it belongs to. - */ - evcon->http_server = http; - TAILQ_INSERT_TAIL(&http->connections, evcon, next); - - if (evhttp_associate_new_request_with_connection(evcon) == -1) - evhttp_connection_free(evcon); -} - - -/* - * Network helper functions that we do not want to export to the rest of - * the world. - */ -#if 0 /* Unused */ -static struct addrinfo * -addr_from_name(char *address) -{ -#ifdef HAVE_GETADDRINFO - struct addrinfo ai, *aitop; - int ai_result; - - memset(&ai, 0, sizeof(ai)); - ai.ai_family = AF_INET; - ai.ai_socktype = SOCK_RAW; - ai.ai_flags = 0; - if ((ai_result = getaddrinfo(address, NULL, &ai, &aitop)) != 0) { - if ( ai_result == EAI_SYSTEM ) - event_warn("getaddrinfo"); - else - event_warnx("getaddrinfo: %s", gai_strerror(ai_result)); - } - - return (aitop); -#else - assert(0); - return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */ -#endif -} -#endif - -static void -name_from_addr(struct sockaddr *sa, socklen_t salen, - char **phost, char **pport) -{ -#ifdef HAVE_GETNAMEINFO - /* XXXX not threadsafe. */ - static char ntop[NI_MAXHOST]; - static char strport[NI_MAXSERV]; - int ni_result; - - if ((ni_result = getnameinfo(sa, salen, - ntop, sizeof(ntop), strport, sizeof(strport), - NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { - if (ni_result == EAI_SYSTEM) - event_err(1, "getnameinfo failed"); - else - event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result)); - } - - *phost = ntop; - *pport = strport; -#else - /* XXXX */ -#endif -} - -/* Either connect or bind */ - -static int -bind_socket_ai(struct addrinfo *ai) -{ - int fd, on = 1, r; - int serrno; - - /* Create listen socket */ - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) { - event_warn("socket"); - return (-1); - } - - if (evutil_make_socket_nonblocking(fd) < 0) - goto out; - -#ifndef WIN32 - if (fcntl(fd, F_SETFD, 1) == -1) { - event_warn("fcntl(F_SETFD)"); - goto out; - } -#endif - - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); - - r = bind(fd, ai->ai_addr, ai->ai_addrlen); - if (r == -1) - goto out; - - return (fd); - - out: - serrno = EVUTIL_SOCKET_ERROR(); - EVUTIL_CLOSESOCKET(fd); - EVUTIL_SET_SOCKET_ERROR(serrno); - return (-1); -} - -static struct addrinfo * -make_addrinfo(const char *address, u_short port) -{ - struct addrinfo *aitop = NULL; - -#ifdef HAVE_GETADDRINFO - struct addrinfo ai; - char strport[NI_MAXSERV]; - int ai_result; - - memset(&ai, 0, sizeof(ai)); - ai.ai_family = AF_INET; - ai.ai_socktype = SOCK_STREAM; - ai.ai_flags = AI_PASSIVE; /* turn NULL host name into INADDR_ANY */ - snprintf(strport, sizeof(strport), "%d", port); - if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) { - if ( ai_result == EAI_SYSTEM ) - event_warn("getaddrinfo"); - else - event_warnx("getaddrinfo: %s", gai_strerror(ai_result)); - return (NULL); - } -#else - static int cur; - static struct addrinfo ai[2]; /* We will be returning the address of some of this memory so it has to last even after this call. */ - if (++cur == 2) cur = 0; /* allow calling this function twice */ - - if (fake_getaddrinfo(address, &ai[cur]) < 0) { - event_warn("fake_getaddrinfo"); - return (NULL); - } - aitop = &ai[cur]; - ((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port); -#endif - - return (aitop); -} - -static int -bind_socket(const char *address, u_short port) -{ - int fd; - struct addrinfo *aitop = make_addrinfo(address, port); - - if (aitop == NULL) - return (-1); - - fd = bind_socket_ai(aitop); - -#ifdef HAVE_GETADDRINFO - freeaddrinfo(aitop); -#else - fake_freeaddrinfo(aitop); -#endif - - return (fd); -} - -static int -socket_connect(int fd, const char *address, unsigned short port) -{ - struct addrinfo *ai = make_addrinfo(address, port); - int res = -1; - - if (ai == NULL) { - event_debug(("%s: make_addrinfo: \"%s:%d\"", - __func__, address, port)); - return (-1); - } - - if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) { -#ifdef WIN32 - int tmp_error = WSAGetLastError(); - if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL && - tmp_error != WSAEINPROGRESS) { - goto out; - } -#else - if (errno != EINPROGRESS) { - goto out; - } -#endif - } - - /* everything is fine */ - res = 0; - -out: -#ifdef HAVE_GETADDRINFO - freeaddrinfo(ai); -#else - fake_freeaddrinfo(ai); -#endif - - return (res); -} diff --git a/extra/libevent/kqueue.c b/extra/libevent/kqueue.c deleted file mode 100644 index 763236e40ac..00000000000 --- a/extra/libevent/kqueue.c +++ /dev/null @@ -1,426 +0,0 @@ -/* $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. 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 - -#ifdef HAVE_WORKING_KQUEUE - -#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> -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#endif - -/* Some platforms apparently define the udata field of struct kevent as - * intptr_t, whereas others define it as void*. There doesn't seem to be an - * easy way to tell them apart via autoconf, so we need to use OS macros. */ -#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) -#define PTR_TO_UDATA(x) ((intptr_t)(x)) -#else -#define PTR_TO_UDATA(x) (x) -#endif - -#include "event.h" -#include "event-internal.h" -#include "log.h" -#include "event-internal.h" - -#define EVLIST_X_KQINKERNEL 0x1000 - -#define NEVENT 64 - -struct kqop { - struct kevent *changes; - int nchanges; - struct kevent *events; - 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 __attribute__((unused))) -{ - int 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; - - /* Check for Mac OS X kqueue bug. */ - kqueueop->changes[0].ident = -1; - kqueueop->changes[0].filter = EVFILT_READ; - kqueueop->changes[0].flags = EV_ADD; - /* - * If kqueue works, then kevent will succeed, and it will - * stick an error in events[0]. If kqueue is broken, then - * kevent will fail. - */ - if (kevent(kq, - kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 || - ((int) kqueueop->events[0].ident) != -1 || - kqueueop->events[0].flags != EV_ERROR) { - event_warn("%s: detected broken kqueue; not using.", __func__); - free(kqueueop->changes); - free(kqueueop->events); - free(kqueueop); - close(kq); - return (NULL); - } - - 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__, kev->ident, - kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", - kev->flags == EV_DELETE ? " (del)" : "")); - - return (0); -} - -static void -kq_sighandler(int sig __attribute__((unused))) -{ - /* Do nothing here */ -} - -static int -kq_dispatch(struct event_base *base __attribute__((unused)), 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); - } - - ev = (struct event *)events[i].udata; - - 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 (!(ev->ev_events & EV_PERSIST)) - ev->ev_flags &= ~EVLIST_X_KQINKERNEL; - - event_active(ev, which, - ev->ev_events & EV_SIGNAL ? events[i].data : 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); - struct timespec timeout = { 0, 0 }; - - memset(&kev, 0, sizeof(kev)); - kev.ident = nsignal; - kev.filter = EVFILT_SIGNAL; - kev.flags = EV_ADD; - if (!(ev->ev_events & EV_PERSIST)) - kev.flags |= EV_ONESHOT; - kev.udata = PTR_TO_UDATA(ev); - - /* 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); - - 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); - - memset(&kev, 0, sizeof(kev)); - kev.ident = nsignal; - kev.filter = EVFILT_SIGNAL; - kev.flags = EV_DELETE; - - if (kq_insert(kqop, &kev) == -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 __attribute__((unused)), 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); -} - -#endif /* HAVE_WORKING_KQUEUE */ diff --git a/extra/libevent/log.c b/extra/libevent/log.c deleted file mode 100644 index aab47182af5..00000000000 --- a/extra/libevent/log.c +++ /dev/null @@ -1,218 +0,0 @@ -/* $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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -#include "misc.h" -#endif -#include <sys/types.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <sys/_time.h> -#endif -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include "event.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); - -static int -event_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - int r; - if (size == 0) - return -1; -#ifdef WIN32 - r = _vsnprintf(str, size, format, args); -#else - r = vsnprintf(str, size, format, args); -#endif - str[size-1] = '\0'; - if (r < 0 || ((size_t)r) >= size) { - /* different platforms behave differently on overflow; - * handle both kinds. */ - return -1; - } - return r; -} - -static int -event_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list ap; - int r; - va_start(ap, format); - r = event_vsnprintf(str, size, format, ap); - va_end(ap); - return r; -} - -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) - event_vsnprintf(buf, sizeof(buf), fmt, ap); - else - buf[0] = '\0'; - - if (log_errno >= 0) { - len = strlen(buf); - if (len < sizeof(buf) - 3) { - event_snprintf(buf + len, sizeof(buf) - len, ": %s", - strerror(log_errno)); - } - } - - event_log(severity, buf); -} - -static event_log_cb log_fn = NULL; - -void -event_set_log_callback(event_log_cb cb) -{ - log_fn = cb; -} - -static void -event_log(int severity, const char *msg) -{ - if (log_fn) - log_fn(severity, msg); - else { - const char *severity_str; - switch (severity) { - case _EVENT_LOG_DEBUG: - severity_str = "debug"; - break; - case _EVENT_LOG_MSG: - severity_str = "msg"; - break; - case _EVENT_LOG_WARN: - severity_str = "warn"; - break; - case _EVENT_LOG_ERR: - severity_str = "err"; - break; - default: - severity_str = "???"; - break; - } - (void)fprintf(stderr, "[%s] %s\n", severity_str, msg); - } -} diff --git a/extra/libevent/log.h b/extra/libevent/log.h deleted file mode 100644 index 7bc6632b8dd..00000000000 --- a/extra/libevent/log.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _LOG_H_ -#define _LOG_H_ - -#ifdef __GNUC__ -#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b))) -#else -#define EV_CHECK_FMT(a,b) -#endif - -void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3); -void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2); -void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3); -void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2); -void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2); -void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2); - -#ifdef USE_DEBUG -#define event_debug(x) _event_debugx x -#else -#define event_debug(x) do {;} while (0) -#endif - -#undef EV_CHECK_FMT - -#endif diff --git a/extra/libevent/min_heap.h b/extra/libevent/min_heap.h deleted file mode 100644 index 389d6dbed4e..00000000000 --- a/extra/libevent/min_heap.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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" - -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 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; - e->min_heap_idx = -1; - min_heap_shift_down_(s, 0u, s->p[--s->n]); - return e; - } - return 0; -} - -int min_heap_erase(min_heap_t* s, struct event* e) -{ - if(((unsigned int)-1) != e->min_heap_idx) - { - min_heap_shift_down_(s, e->min_heap_idx, s->p[--s->n]); - e->min_heap_idx = -1; - return 0; - } - return -1; -} - -int min_heap_reserve(min_heap_t* s, unsigned n) -{ - if(s->a < n) - { - struct event** p; - unsigned a = s->a ? s->a * 2 : 8; - if(a < n) - a = n; - if(!(p = (struct event**)realloc(s->p, a * sizeof *p))) - return -1; - s->p = p; - s->a = a; - } - return 0; -} - -void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e) -{ - unsigned parent = (hole_index - 1) / 2; - while(hole_index && min_heap_elem_greater(s->p[parent], e)) - { - (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index; - hole_index = parent; - parent = (hole_index - 1) / 2; - } - (s->p[hole_index] = e)->min_heap_idx = hole_index; -} - -void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e) -{ - unsigned min_child = 2 * (hole_index + 1); - while(min_child <= s->n) - { - min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]); - if(!(min_heap_elem_greater(e, s->p[min_child]))) - break; - (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index; - hole_index = min_child; - min_child = 2 * (hole_index + 1); - } - min_heap_shift_up_(s, hole_index, e); -} - -#endif /* _MIN_HEAP_H_ */ diff --git a/extra/libevent/poll.c b/extra/libevent/poll.c deleted file mode 100644 index 6c99e2ca79b..00000000000 --- a/extra/libevent/poll.c +++ /dev/null @@ -1,378 +0,0 @@ -/* $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. 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 - -#ifdef HAVE_POLL - -#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); -} - -#endif /* HAVE_POLL */ diff --git a/extra/libevent/select.c b/extra/libevent/select.c deleted file mode 100644 index b8bd1a1c361..00000000000 --- a/extra/libevent/select.c +++ /dev/null @@ -1,356 +0,0 @@ -/* $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. 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 - -#ifdef HAVE_SELECT - -#include <sys/types.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <sys/_time.h> -#endif -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif -#include <sys/queue.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" - -#ifndef howmany -#define howmany(x, y) (((x)+((y)-1))/(y)) -#endif - -struct selectop { - int event_fds; /* Highest fd in fd set */ - int event_fdsz; - fd_set *event_readset_in; - fd_set *event_writeset_in; - fd_set *event_readset_out; - fd_set *event_writeset_out; - struct event **event_r_by_fd; - struct event **event_w_by_fd; -}; - -static void *select_init (struct event_base *); -static int select_add (void *, struct event *); -static int select_del (void *, struct event *); -static int select_dispatch (struct event_base *, void *, struct timeval *); -static void select_dealloc (struct event_base *, void *); - -const struct eventop selectops = { - "select", - select_init, - select_add, - select_del, - select_dispatch, - select_dealloc, - 0 -}; - -static int select_resize(struct selectop *sop, int fdsz); - -static void * -select_init(struct event_base *base) -{ - struct selectop *sop; - - /* Disable select when this environment variable is set */ - if (getenv("EVENT_NOSELECT")) - return (NULL); - - if (!(sop = calloc(1, sizeof(struct selectop)))) - return (NULL); - - select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); - - evsignal_init(base); - - return (sop); -} - -#ifdef CHECK_INVARIANTS -static void -check_selectop(struct selectop *sop) -{ - int i; - for (i = 0; i <= sop->event_fds; ++i) { - if (FD_ISSET(i, sop->event_readset_in)) { - assert(sop->event_r_by_fd[i]); - assert(sop->event_r_by_fd[i]->ev_events & EV_READ); - assert(sop->event_r_by_fd[i]->ev_fd == i); - } else { - assert(! sop->event_r_by_fd[i]); - } - if (FD_ISSET(i, sop->event_writeset_in)) { - assert(sop->event_w_by_fd[i]); - assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE); - assert(sop->event_w_by_fd[i]->ev_fd == i); - } else { - assert(! sop->event_w_by_fd[i]); - } - } - -} -#else -#define check_selectop(sop) do { (void) sop; } while (0) -#endif - -static int -select_dispatch(struct event_base *base, void *arg, struct timeval *tv) -{ - int res, i; - struct selectop *sop = arg; - - check_selectop(sop); - - memcpy(sop->event_readset_out, sop->event_readset_in, - sop->event_fdsz); - memcpy(sop->event_writeset_out, sop->event_writeset_in, - sop->event_fdsz); - - res = select(sop->event_fds + 1, sop->event_readset_out, - sop->event_writeset_out, NULL, tv); - - check_selectop(sop); - - if (res == -1) { - if (errno != EINTR) { - event_warn("select"); - return (-1); - } - - evsignal_process(base); - return (0); - } else if (base->sig.evsignal_caught) { - evsignal_process(base); - } - - event_debug(("%s: select reports %d", __func__, res)); - - check_selectop(sop); - for (i = 0; i <= sop->event_fds; ++i) { - struct event *r_ev = NULL, *w_ev = NULL; - res = 0; - if (FD_ISSET(i, sop->event_readset_out)) { - r_ev = sop->event_r_by_fd[i]; - res |= EV_READ; - } - if (FD_ISSET(i, sop->event_writeset_out)) { - w_ev = sop->event_w_by_fd[i]; - res |= EV_WRITE; - } - 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); - } - } - check_selectop(sop); - - return (0); -} - - -static int -select_resize(struct selectop *sop, int fdsz) -{ - int n_events, n_events_old; - - fd_set *readset_in = NULL; - fd_set *writeset_in = NULL; - fd_set *readset_out = NULL; - fd_set *writeset_out = NULL; - struct event **r_by_fd = NULL; - struct event **w_by_fd = NULL; - - n_events = (fdsz/sizeof(fd_mask)) * NFDBITS; - n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS; - - if (sop->event_readset_in) - check_selectop(sop); - - if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL) - goto error; - sop->event_readset_in = readset_in; - if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL) - goto error; - sop->event_readset_out = readset_out; - if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL) - goto error; - sop->event_writeset_in = writeset_in; - if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL) - goto error; - sop->event_writeset_out = writeset_out; - if ((r_by_fd = realloc(sop->event_r_by_fd, - n_events*sizeof(struct event*))) == NULL) - goto error; - sop->event_r_by_fd = r_by_fd; - if ((w_by_fd = realloc(sop->event_w_by_fd, - n_events * sizeof(struct event*))) == NULL) - goto error; - sop->event_w_by_fd = w_by_fd; - - memset((char *)sop->event_readset_in + sop->event_fdsz, 0, - fdsz - sop->event_fdsz); - memset((char *)sop->event_writeset_in + sop->event_fdsz, 0, - fdsz - sop->event_fdsz); - memset(sop->event_r_by_fd + n_events_old, 0, - (n_events-n_events_old) * sizeof(struct event*)); - memset(sop->event_w_by_fd + n_events_old, 0, - (n_events-n_events_old) * sizeof(struct event*)); - - sop->event_fdsz = fdsz; - check_selectop(sop); - - return (0); - - error: - event_warn("malloc"); - return (-1); -} - - -static int -select_add(void *arg, struct event *ev) -{ - struct selectop *sop = arg; - - if (ev->ev_events & EV_SIGNAL) - return (evsignal_add(ev)); - - check_selectop(sop); - /* - * Keep track of the highest fd, so that we can calculate the size - * of the fd_sets for select(2) - */ - if (sop->event_fds < ev->ev_fd) { - unsigned int fdsz = sop->event_fdsz; - - if (fdsz < sizeof(fd_mask)) - fdsz = sizeof(fd_mask); - - while (fdsz < - (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask))) - fdsz *= 2; - - if (fdsz != (unsigned int) sop->event_fdsz) { - if (select_resize(sop, fdsz)) { - check_selectop(sop); - return (-1); - } - } - - sop->event_fds = ev->ev_fd; - } - - if (ev->ev_events & EV_READ) { - FD_SET(ev->ev_fd, sop->event_readset_in); - sop->event_r_by_fd[ev->ev_fd] = ev; - } - if (ev->ev_events & EV_WRITE) { - FD_SET(ev->ev_fd, sop->event_writeset_in); - sop->event_w_by_fd[ev->ev_fd] = ev; - } - check_selectop(sop); - - return (0); -} - -/* - * Nothing to be done here. - */ - -static int -select_del(void *arg, struct event *ev) -{ - struct selectop *sop = arg; - - check_selectop(sop); - if (ev->ev_events & EV_SIGNAL) - return (evsignal_del(ev)); - - if (sop->event_fds < ev->ev_fd) { - check_selectop(sop); - return (0); - } - - if (ev->ev_events & EV_READ) { - FD_CLR(ev->ev_fd, sop->event_readset_in); - sop->event_r_by_fd[ev->ev_fd] = NULL; - } - - if (ev->ev_events & EV_WRITE) { - FD_CLR(ev->ev_fd, sop->event_writeset_in); - sop->event_w_by_fd[ev->ev_fd] = NULL; - } - - check_selectop(sop); - return (0); -} - -static void -select_dealloc(struct event_base *base, void *arg) -{ - struct selectop *sop = arg; - - evsignal_dealloc(base); - if (sop->event_readset_in) - free(sop->event_readset_in); - if (sop->event_writeset_in) - free(sop->event_writeset_in); - if (sop->event_readset_out) - free(sop->event_readset_out); - if (sop->event_writeset_out) - free(sop->event_writeset_out); - if (sop->event_r_by_fd) - free(sop->event_r_by_fd); - if (sop->event_w_by_fd) - free(sop->event_w_by_fd); - - memset(sop, 0, sizeof(struct selectop)); - free(sop); -} - -#endif /* HAVE_SELECT */ diff --git a/extra/libevent/signal.c b/extra/libevent/signal.c deleted file mode 100644 index ce164f2f5ea..00000000000 --- a/extra/libevent/signal.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $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. 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 - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winsock2.h> -#undef WIN32_LEAN_AND_MEAN -#endif -#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 __attribute__((unused)), - void *arg __attribute__((unused))) -{ - static char signals[100]; -#ifdef WIN32 - SSIZE_T n; -#else - ssize_t n; -#endif - - 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) -{ - /* - * 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); - - 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) { - event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", - __func__, evsignal, sig->sh_old_max)); - sig->sh_old_max = evsignal + 1; - p = realloc(sig->sh_old, sig->sh_old_max * sizeof *sig->sh_old); - if (p == NULL) { - event_warn("realloc"); - return (-1); - } - 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); - - 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) { - sig->ev_signal_added = 1; - event_add(&sig->ev_signal, NULL); - } - - 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) -{ - 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 event *ev; - sig_atomic_t ncalls; - - base->sig.evsignal_caught = 0; - TAILQ_FOREACH(ev, &base->sig.signalqueue, ev_signal_next) { - ncalls = base->sig.evsigcaught[EVENT_SIGNAL(ev)]; - if (ncalls) { - if (!(ev->ev_events & EV_PERSIST)) - event_del(ev); - event_active(ev, EV_SIGNAL, ncalls); - base->sig.evsigcaught[EVENT_SIGNAL(ev)] = 0; - } - } -} - -void -evsignal_dealloc(struct event_base *base) -{ - if(base->sig.ev_signal_added) { - event_del(&base->sig.ev_signal); - base->sig.ev_signal_added = 0; - } - assert(TAILQ_EMPTY(&base->sig.signalqueue)); - - 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); -} diff --git a/extra/libevent/strlcpy-internal.h b/extra/libevent/strlcpy-internal.h deleted file mode 100644 index 22b5f61d45e..00000000000 --- a/extra/libevent/strlcpy-internal.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _STRLCPY_INTERNAL_H_ -#define _STRLCPY_INTERNAL_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifndef HAVE_STRLCPY -#include <string.h> -size_t _event_strlcpy(char *dst, const char *src, size_t siz); -#define strlcpy _event_strlcpy -#endif - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/extra/libevent/strlcpy.c b/extra/libevent/strlcpy.c deleted file mode 100644 index 5d194527c8c..00000000000 --- a/extra/libevent/strlcpy.c +++ /dev/null @@ -1,76 +0,0 @@ -/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ - -/* - * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.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 ``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. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; -#endif /* LIBC_SCCS and not lint */ - -#include <sys/types.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ - -#ifndef HAVE_STRLCPY -#include "strlcpy-internal.h" - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -_event_strlcpy(dst, src, siz) - char *dst; - const char *src; - size_t siz; -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} -#endif |