summaryrefslogtreecommitdiff
path: root/libs/libevent/src
diff options
context:
space:
mode:
authorKirill Volinsky <Mataes2007@gmail.com>2017-11-29 09:33:41 +0300
committerKirill Volinsky <Mataes2007@gmail.com>2017-11-29 09:33:41 +0300
commit89f3cf8bbb9dc1fa0fe72f6af6638ac086c7e011 (patch)
tree5be9a7ae2255b9ad420bed266b90b1f98059964a /libs/libevent/src
parente28c4adb361a87e143eb8cb2af449e3bcb3375b1 (diff)
libevent, telegram, whatsapp moved to deprecated coz doesn't work
Diffstat (limited to 'libs/libevent/src')
-rw-r--r--libs/libevent/src/WIN32-Code/getopt.c149
-rw-r--r--libs/libevent/src/WIN32-Code/getopt.h33
-rw-r--r--libs/libevent/src/WIN32-Code/getopt_long.c233
-rw-r--r--libs/libevent/src/WIN32-Code/nmake/evconfig-private.h6
-rw-r--r--libs/libevent/src/WIN32-Code/nmake/event2/event-config.h360
-rw-r--r--libs/libevent/src/WIN32-Code/tree.h677
-rw-r--r--libs/libevent/src/arc4random.cxx556
-rw-r--r--libs/libevent/src/buffer.c3439
-rw-r--r--libs/libevent/src/buffer_iocp.c326
-rw-r--r--libs/libevent/src/bufferevent-internal.h480
-rw-r--r--libs/libevent/src/bufferevent.c1016
-rw-r--r--libs/libevent/src/bufferevent_async.c686
-rw-r--r--libs/libevent/src/bufferevent_filter.c555
-rw-r--r--libs/libevent/src/bufferevent_openssl.c1484
-rw-r--r--libs/libevent/src/bufferevent_pair.c360
-rw-r--r--libs/libevent/src/bufferevent_ratelim.c1092
-rw-r--r--libs/libevent/src/bufferevent_sock.c707
-rw-r--r--libs/libevent/src/changelist-internal.h102
-rw-r--r--libs/libevent/src/compat/sys/queue.h488
-rw-r--r--libs/libevent/src/defer-internal.h70
-rw-r--r--libs/libevent/src/epolltable-internal.h1166
-rw-r--r--libs/libevent/src/evbuffer-internal.h351
-rw-r--r--libs/libevent/src/evdns.c4761
-rw-r--r--libs/libevent/src/event-internal.h479
-rw-r--r--libs/libevent/src/event.c3940
-rw-r--r--libs/libevent/src/event_iocp.c294
-rw-r--r--libs/libevent/src/event_tagging.c605
-rw-r--r--libs/libevent/src/evmap-internal.h117
-rw-r--r--libs/libevent/src/evmap.c1055
-rw-r--r--libs/libevent/src/evrpc-internal.h205
-rw-r--r--libs/libevent/src/evrpc.c1171
-rw-r--r--libs/libevent/src/evsignal-internal.h65
-rw-r--r--libs/libevent/src/evthread-internal.h392
-rw-r--r--libs/libevent/src/evthread.c509
-rw-r--r--libs/libevent/src/evthread_win32.c341
-rw-r--r--libs/libevent/src/evutil.c2666
-rw-r--r--libs/libevent/src/evutil_rand.c206
-rw-r--r--libs/libevent/src/evutil_time.c538
-rw-r--r--libs/libevent/src/ht-internal.h487
-rw-r--r--libs/libevent/src/http-internal.h200
-rw-r--r--libs/libevent/src/http.c4892
-rw-r--r--libs/libevent/src/iocp-internal.h201
-rw-r--r--libs/libevent/src/ipv6-internal.h83
-rw-r--r--libs/libevent/src/listener.c889
-rw-r--r--libs/libevent/src/log-internal.h83
-rw-r--r--libs/libevent/src/log.c253
-rw-r--r--libs/libevent/src/minheap-internal.h188
-rw-r--r--libs/libevent/src/mm-internal.h87
-rw-r--r--libs/libevent/src/ratelim-internal.h105
-rw-r--r--libs/libevent/src/signal.c479
-rw-r--r--libs/libevent/src/stdafx.cxx2
-rw-r--r--libs/libevent/src/stdafx.h2
-rw-r--r--libs/libevent/src/strlcpy-internal.h22
-rw-r--r--libs/libevent/src/strlcpy.c75
-rw-r--r--libs/libevent/src/time-internal.h98
-rw-r--r--libs/libevent/src/util-internal.h485
-rw-r--r--libs/libevent/src/win32select.c388
57 files changed, 0 insertions, 40699 deletions
diff --git a/libs/libevent/src/WIN32-Code/getopt.c b/libs/libevent/src/WIN32-Code/getopt.c
deleted file mode 100644
index 0fcba5d915..0000000000
--- a/libs/libevent/src/WIN32-Code/getopt.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* $NetBSD: getopt.c,v 1.16 1999/12/02 13:15:56 kleink Exp $ */
-
-/*
- * Copyright (c) 1987, 1993, 1994, 1995
- * 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 names of the copyright holders 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 COPYRIGHT HOLDERS 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.
- */
-
-#if 0
-static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
-#endif
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#define __P(x) x
-#define _DIAGASSERT(x) assert(x)
-
-#ifdef __weak_alias
-__weak_alias(getopt,_getopt);
-#endif
-
-
-int opterr = 1, /* if error message should be printed */
- optind = 1, /* index into parent argv vector */
- optopt, /* character checked for validity */
- optreset; /* reset getopt */
-char *optarg; /* argument associated with option */
-
-static char * _progname __P((char *));
-int getopt_internal __P((int, char * const *, const char *));
-
-static char *
-_progname(nargv0)
- char * nargv0;
-{
- char * tmp;
-
- _DIAGASSERT(nargv0 != NULL);
-
- tmp = strrchr(nargv0, '/');
- if (tmp)
- tmp++;
- else
- tmp = nargv0;
- return(tmp);
-}
-
-#define BADCH (int)'?'
-#define BADARG (int)':'
-#define EMSG ""
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt(nargc, nargv, ostr)
- int nargc;
- char * const nargv[];
- const char *ostr;
-{
- static char *__progname = 0;
- static char *place = EMSG; /* option letter processing */
- char *oli; /* option letter list index */
- __progname = __progname?__progname:_progname(*nargv);
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(ostr != NULL);
-
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc || *(place = nargv[optind]) != '-') {
- place = EMSG;
- return (-1);
- }
- if (place[1] && *++place == '-' /* found "--" */
- && place[1] == '\0') {
- ++optind;
- place = EMSG;
- return (-1);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
- /*
- * if the user didn't specify '-' as an option,
- * assume it means -1.
- */
- if (optopt == (int)'-')
- return (-1);
- if (!*place)
- ++optind;
- if (opterr && *ostr != ':')
- (void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname, optopt);
- return (BADCH);
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- }
- else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- if (*ostr == ':')
- return (BADARG);
- if (opterr)
- (void)fprintf(stderr,
- "%s: option requires an argument -- %c\n",
- __progname, optopt);
- return (BADCH);
- }
- else /* white space */
- optarg = nargv[optind];
- place = EMSG;
- ++optind;
- }
- return (optopt); /* dump back option letter */
-}
-
diff --git a/libs/libevent/src/WIN32-Code/getopt.h b/libs/libevent/src/WIN32-Code/getopt.h
deleted file mode 100644
index 796f455050..0000000000
--- a/libs/libevent/src/WIN32-Code/getopt.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __GETOPT_H__
-#define __GETOPT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int opterr; /* if error message should be printed */
-extern int optind; /* index into parent argv vector */
-extern int optopt; /* character checked for validity */
-extern int optreset; /* reset getopt */
-extern char *optarg; /* argument associated with option */
-
-struct option
-{
- const char *name;
- int has_arg;
- int *flag;
- int val;
-};
-
-#define no_argument 0
-#define required_argument 1
-#define optional_argument 2
-
-int getopt(int, char**, const char*);
-int getopt_long(int, char**, const char*, const struct option*, int*);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __GETOPT_H__ */
diff --git a/libs/libevent/src/WIN32-Code/getopt_long.c b/libs/libevent/src/WIN32-Code/getopt_long.c
deleted file mode 100644
index 03f0c01a15..0000000000
--- a/libs/libevent/src/WIN32-Code/getopt_long.c
+++ /dev/null
@@ -1,233 +0,0 @@
-
-/*
- * Copyright (c) 1987, 1993, 1994, 1996
- * 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 names of the copyright holders 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 COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
- * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "getopt.h"
-
-extern int opterr; /* if error message should be printed */
-extern int optind; /* index into parent argv vector */
-extern int optopt; /* character checked for validity */
-extern int optreset; /* reset getopt */
-extern char *optarg; /* argument associated with option */
-
-#define __P(x) x
-#define _DIAGASSERT(x) assert(x)
-
-static char * __progname __P((char *));
-int getopt_internal __P((int, char * const *, const char *));
-
-static char *
-__progname(nargv0)
- char * nargv0;
-{
- char * tmp;
-
- _DIAGASSERT(nargv0 != NULL);
-
- tmp = strrchr(nargv0, '/');
- if (tmp)
- tmp++;
- else
- tmp = nargv0;
- return(tmp);
-}
-
-#define BADCH (int)'?'
-#define BADARG (int)':'
-#define EMSG ""
-
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt_internal(nargc, nargv, ostr)
- int nargc;
- char * const *nargv;
- const char *ostr;
-{
- static char *place = EMSG; /* option letter processing */
- char *oli; /* option letter list index */
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(ostr != NULL);
-
- if (optreset || !*place) { /* update scanning pointer */
- optreset = 0;
- if (optind >= nargc || *(place = nargv[optind]) != '-') {
- place = EMSG;
- return (-1);
- }
- if (place[1] && *++place == '-') { /* found "--" */
- /* ++optind; */
- place = EMSG;
- return (-2);
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' ||
- !(oli = strchr(ostr, optopt))) {
- /*
- * if the user didn't specify '-' as an option,
- * assume it means -1.
- */
- if (optopt == (int)'-')
- return (-1);
- if (!*place)
- ++optind;
- if (opterr && *ostr != ':')
- (void)fprintf(stderr,
- "%s: illegal option -- %c\n", __progname(nargv[0]), optopt);
- return (BADCH);
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- } else { /* need an argument */
- if (*place) /* no white space */
- optarg = place;
- else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- if ((opterr) && (*ostr != ':'))
- (void)fprintf(stderr,
- "%s: option requires an argument -- %c\n",
- __progname(nargv[0]), optopt);
- return (BADARG);
- } else /* white space */
- optarg = nargv[optind];
- place = EMSG;
- ++optind;
- }
- return (optopt); /* dump back option letter */
-}
-
-#if 0
-/*
- * getopt --
- * Parse argc/argv argument vector.
- */
-int
-getopt2(nargc, nargv, ostr)
- int nargc;
- char * const *nargv;
- const char *ostr;
-{
- int retval;
-
- if ((retval = getopt_internal(nargc, nargv, ostr)) == -2) {
- retval = -1;
- ++optind;
- }
- return(retval);
-}
-#endif
-
-/*
- * getopt_long --
- * Parse argc/argv argument vector.
- */
-int
-getopt_long(nargc, nargv, options, long_options, index)
- int nargc;
- char ** nargv;
- const char * options;
- const struct option * long_options;
- int * index;
-{
- int retval;
-
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(options != NULL);
- _DIAGASSERT(long_options != NULL);
- /* index may be NULL */
-
- if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
- char *current_argv = nargv[optind++] + 2, *has_equal;
- int i, current_argv_len, match = -1;
-
- if (*current_argv == '\0') {
- return(-1);
- }
- if ((has_equal = strchr(current_argv, '=')) != NULL) {
- current_argv_len = has_equal - current_argv;
- has_equal++;
- } else
- current_argv_len = strlen(current_argv);
-
- for (i = 0; long_options[i].name; i++) {
- if (strncmp(current_argv, long_options[i].name, current_argv_len))
- continue;
-
- if (strlen(long_options[i].name) == (unsigned)current_argv_len) {
- match = i;
- break;
- }
- if (match == -1)
- match = i;
- }
- if (match != -1) {
- if (long_options[match].has_arg == required_argument ||
- long_options[match].has_arg == optional_argument) {
- if (has_equal)
- optarg = has_equal;
- else
- optarg = nargv[optind++];
- }
- if ((long_options[match].has_arg == required_argument)
- && (optarg == NULL)) {
- /*
- * Missing argument, leading :
- * indicates no error should be generated
- */
- if ((opterr) && (*options != ':'))
- (void)fprintf(stderr,
- "%s: option requires an argument -- %s\n",
- __progname(nargv[0]), current_argv);
- return (BADARG);
- }
- } else { /* No matching argument */
- if ((opterr) && (*options != ':'))
- (void)fprintf(stderr,
- "%s: illegal option -- %s\n", __progname(nargv[0]), current_argv);
- return (BADCH);
- }
- if (long_options[match].flag) {
- *long_options[match].flag = long_options[match].val;
- retval = 0;
- } else
- retval = long_options[match].val;
- if (index)
- *index = match;
- }
- return(retval);
-}
diff --git a/libs/libevent/src/WIN32-Code/nmake/evconfig-private.h b/libs/libevent/src/WIN32-Code/nmake/evconfig-private.h
deleted file mode 100644
index 88e206272b..0000000000
--- a/libs/libevent/src/WIN32-Code/nmake/evconfig-private.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#if !defined(EVENT_EVCONFIG__PRIVATE_H_) && !defined(__MINGW32__)
-#define EVENT_EVCONFIG__PRIVATE_H_
-
-/* Nothing to see here. Move along. */
-
-#endif
diff --git a/libs/libevent/src/WIN32-Code/nmake/event2/event-config.h b/libs/libevent/src/WIN32-Code/nmake/event2/event-config.h
deleted file mode 100644
index 8cbf190289..0000000000
--- a/libs/libevent/src/WIN32-Code/nmake/event2/event-config.h
+++ /dev/null
@@ -1,360 +0,0 @@
-/* event2/event-config.h
- *
- * This file was generated by autoconf when libevent was built, and post-
- * processed by Libevent so that its macros would have a uniform prefix.
- *
- * DO NOT EDIT THIS FILE.
- *
- * Do not rely on macros in this file existing in later versions.
- */
-#ifndef EVENT_CONFIG_H__
-#define EVENT_CONFIG_H__
-/* config.h. Generated by configure. */
-/* config.h.in. Generated from configure.in by autoheader. */
-
-/* Define if libevent should not allow replacing the mm functions */
-/* #undef EVENT__DISABLE_MM_REPLACEMENT */
-
-/* Define if libevent should not be compiled with thread support */
-/* #undef EVENT__DISABLE_THREAD_SUPPORT */
-
-/* Define if clock_gettime is available in libc */
-/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */
-
-/* Define is no secure id variant is available */
-/* #define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1 */
-#define EVENT_DNS_USE_FTIME_FOR_ID_ 1
-
-/* Define to 1 if you have the <arpa/inet.h> header file. */
-/* #undef EVENT__HAVE_ARPA_INET_H */
-
-/* Define to 1 if you have the `clock_gettime' function. */
-/* #undef EVENT__HAVE_CLOCK_GETTIME */
-
-/* Define if /dev/poll is available */
-/* #undef EVENT__HAVE_DEVPOLL */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-/* #undef EVENT__HAVE_DLFCN_H */
-
-/* Define if your system supports the epoll system calls */
-/* #undef EVENT__HAVE_EPOLL */
-
-/* Define to 1 if you have the `epoll_ctl' function. */
-/* #undef EVENT__HAVE_EPOLL_CTL */
-
-/* Define to 1 if you have the `eventfd' function. */
-/* #undef EVENT__HAVE_EVENTFD */
-
-/* Define if your system supports event ports */
-/* #undef EVENT__HAVE_EVENT_PORTS */
-
-/* Define to 1 if you have the `fcntl' function. */
-/* #undef EVENT__HAVE_FCNTL */
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define EVENT__HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `getaddrinfo' function. */
-#define EVENT__HAVE_GETADDRINFO 1
-
-/* Define to 1 if you have the `getnameinfo' function. */
-#define EVENT__HAVE_GETNAMEINFO 1
-
-/* Define to 1 if you have the `getprotobynumber' function. */
-#define EVENT__HAVE_GETPROTOBYNUMBER 1
-
-/* Define to 1 if you have the `getservbyname' function. */
-#define EVENT__HAVE_GETSERVBYNAME 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-/* #define EVENT__HAVE_GETTIMEOFDAY 1 */
-
-/* Define to 1 if you have the `inet_ntop' function. */
-/* #undef EVENT__HAVE_INET_NTOP */
-
-/* Define to 1 if you have the `inet_pton' function. */
-/* #undef EVENT__HAVE_INET_PTON */
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-/* #define EVENT__HAVE_INTTYPES_H 1 */
-
-/* Define to 1 if you have the `kqueue' function. */
-/* #undef EVENT__HAVE_KQUEUE */
-
-/* Define if the system has zlib */
-/* #undef EVENT__HAVE_LIBZ */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define EVENT__HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the `mmap' function. */
-/* #undef EVENT__HAVE_MMAP */
-
-/* Define to 1 if you have the <netinet/in6.h> header file. */
-/* #undef EVENT__HAVE_NETINET_IN6_H */
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-/* #undef EVENT__HAVE_NETINET_IN_H */
-
-/* Define to 1 if you have the `pipe' function. */
-/* #undef EVENT__HAVE_PIPE */
-
-/* Define to 1 if you have the `poll' function. */
-/* #undef EVENT__HAVE_POLL */
-
-/* Define to 1 if you have the <poll.h> header file. */
-/* #undef EVENT__HAVE_POLL_H */
-
-/* Define to 1 if you have the `port_create' function. */
-/* #undef EVENT__HAVE_PORT_CREATE */
-
-/* Define to 1 if you have the <port.h> header file. */
-/* #undef EVENT__HAVE_PORT_H */
-
-/* Define if you have POSIX threads libraries and header files. */
-/* #undef EVENT__HAVE_PTHREAD */
-
-/* Define if we have pthreads on this system */
-/* #undef EVENT__HAVE_PTHREADS */
-
-/* Define to 1 if the system has the type `sa_family_t'. */
-/* #undef EVENT__HAVE_SA_FAMILY_T */
-
-/* Define to 1 if you have the `select' function. */
-/* #undef EVENT__HAVE_SELECT */
-
-/* Define to 1 if you have the `sendfile' function. */
-/* #undef EVENT__HAVE_SENDFILE */
-
-/* Define if F_SETFD is defined in <fcntl.h> */
-/* #undef EVENT__HAVE_SETFD */
-
-/* Define to 1 if you have the `sigaction' function. */
-/* #undef EVENT__HAVE_SIGACTION */
-
-/* Define to 1 if you have the `signal' function. */
-#define EVENT__HAVE_SIGNAL 1
-
-/* Define to 1 if you have the `splice' function. */
-/* #undef EVENT__HAVE_SPLICE */
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define EVENT__HAVE_STDARG_H 1
-
-/* Define to 1 if you have the <stddef.h> header file. */
-#define EVENT__HAVE_STDDEF_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-/* #define EVENT__HAVE_STDINT_H 1 */
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define EVENT__HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define EVENT__HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define EVENT__HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-/* #undef EVENT__HAVE_STRLCPY */
-
-/* Define to 1 if you have the `strsep' function. */
-/* #undef EVENT__HAVE_STRSEP */
-
-/* Define to 1 if you have the `strtok_r' function. */
-/* #undef EVENT__HAVE_STRTOK_R */
-
-/* Define to 1 if you have the `strtoll' function. */
-/* #define EVENT__HAVE_STRTOLL 1 */
-
-#define EVENT__HAVE_STRUCT_ADDRINFO 1
-
-/* Define to 1 if the system has the type `struct in6_addr'. */
-#define EVENT__HAVE_STRUCT_IN6_ADDR 1
-
-/* Define to 1 if `s6_addr16' is member of `struct in6_addr'. */
-#define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR16 1
-
-/* Define to 1 if `s6_addr32' is member of `struct in6_addr'. */
-#define EVENT__HAVE_STRUCT_IN6_ADDR_S6_ADDR32 1
-
-/* Define to 1 if the system has the type `struct sockaddr_in6'. */
-#define EVENT__HAVE_STRUCT_SOCKADDR_IN6 1
-
-/* Define to 1 if `sin6_len' is member of `struct sockaddr_in6'. */
-/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN */
-
-/* Define to 1 if `sin_len' is member of `struct sockaddr_in'. */
-/* #undef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
-
-/* Define to 1 if the system has the type `struct sockaddr_storage'. */
-#define EVENT__HAVE_STRUCT_SOCKADDR_STORAGE 1
-
-/* Define to 1 if you have the <sys/devpoll.h> header file. */
-/* #undef EVENT__HAVE_SYS_DEVPOLL_H */
-
-/* Define to 1 if you have the <sys/epoll.h> header file. */
-/* #undef EVENT__HAVE_SYS_EPOLL_H */
-
-/* Define to 1 if you have the <sys/eventfd.h> header file. */
-/* #undef EVENT__HAVE_SYS_EVENTFD_H */
-
-/* Define to 1 if you have the <sys/event.h> header file. */
-/* #undef EVENT__HAVE_SYS_EVENT_H */
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-/* #undef EVENT__HAVE_SYS_IOCTL_H */
-
-/* Define to 1 if you have the <sys/mman.h> header file. */
-/* #undef EVENT__HAVE_SYS_MMAN_H */
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-/* #define EVENT__HAVE_SYS_PARAM_H 1 */
-
-/* Define to 1 if you have the <sys/queue.h> header file. */
-/* #undef EVENT__HAVE_SYS_QUEUE_H */
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-/* #undef EVENT__HAVE_SYS_SELECT_H */
-
-/* Define to 1 if you have the <sys/sendfile.h> header file. */
-/* #undef EVENT__HAVE_SYS_SENDFILE_H */
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-/* #undef EVENT__HAVE_SYS_SOCKET_H */
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define EVENT__HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-/* #define EVENT__HAVE_SYS_TIME_H 1 */
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define EVENT__HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/uio.h> header file. */
-/* #undef EVENT__HAVE_SYS_UIO_H */
-
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-/* #undef EVENT__HAVE_TAILQFOREACH */
-
-/* Define if timeradd is defined in <sys/time.h> */
-/* #undef EVENT__HAVE_TIMERADD */
-
-/* Define if timerclear is defined in <sys/time.h> */
-#define EVENT__HAVE_TIMERCLEAR 1
-
-/* Define if timercmp is defined in <sys/time.h> */
-#define EVENT__HAVE_TIMERCMP 1
-
-/* Define if timerisset is defined in <sys/time.h> */
-#define EVENT__HAVE_TIMERISSET 1
-
-/* Define to 1 if the system has the type `uint16_t'. */
-/* #define EVENT__HAVE_UINT16_T 1 */
-
-/* Define to 1 if the system has the type `uint32_t'. */
-/* #define EVENT__HAVE_UINT32_T 1 */
-
-/* Define to 1 if the system has the type `uint64_t'. */
-/* #define EVENT__HAVE_UINT64_T 1 */
-
-/* Define to 1 if the system has the type `uint8_t'. */
-/* #define EVENT__HAVE_UINT8_T 1 */
-
-/* Define to 1 if you have the <unistd.h> header file. */
-/* #define EVENT__HAVE_UNISTD_H 1 */
-
-/* Define to 1 if you have the `vasprintf' function. */
-/* #undef EVENT__HAVE_VASPRINTF */
-
-/* Define if kqueue works correctly with pipes */
-/* #undef EVENT__HAVE_WORKING_KQUEUE */
-
-/* Numeric representation of the version */
-#define EVENT__NUMERIC_VERSION 0x02010500
-
-/* Name of package */
-#define EVENT__PACKAGE "libevent"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define EVENT__PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define EVENT__PACKAGE_NAME ""
-
-/* Define to the full name and version of this package. */
-#define EVENT__PACKAGE_STRING ""
-
-/* Define to the one symbol short name of this package. */
-#define EVENT__PACKAGE_TARNAME ""
-
-/* Define to the version of this package. */
-#define EVENT__PACKAGE_VERSION ""
-
-/* Define to necessary symbol if this constant uses a non-standard name on
- your system. */
-/* #undef EVENT__PTHREAD_CREATE_JOINABLE */
-
-/* The size of a `int', as computed by sizeof. */
-#define EVENT__SIZEOF_INT 4
-
-/* The size of a `long', as computed by sizeof. */
-#define EVENT__SIZEOF_LONG 4
-
-/* The size of a `long long', as computed by sizeof. */
-#define EVENT__SIZEOF_LONG_LONG 8
-
-/* The size of a `short', as computed by sizeof. */
-#define EVENT__SIZEOF_SHORT 2
-
-/* The size of `size_t', as computed by sizeof. */
-#ifdef _WIN64
-#define EVENT__SIZEOF_SIZE_T 8
-#else
-#define EVENT__SIZEOF_SIZE_T 4
-#endif
-
-/* The size of `void *', as computed by sizeof. */
-#ifdef _WIN64
-#define EVENT__SIZEOF_VOID_P 8
-#else
-#define EVENT__SIZEOF_VOID_P 4
-#endif
-
-/* Define to 1 if you have the ANSI C header files. */
-#define EVENT__STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define EVENT__TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define EVENT__VERSION "2.1.5-beta"
-
-/* Define to appropriate substitue if compiler doesnt have __func__ */
-#define EVENT____func__ __FUNCTION__
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef EVENT__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 _EVENT___cplusplus
-#define EVENT__inline __inline
-#endif
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef EVENT__pid_t */
-
-/* Define to `unsigned' if <sys/types.h> does not define. */
-/* #undef EVENT__size_t */
-
-/* Define to unsigned int if you dont have it */
-#define EVENT__socklen_t unsigned int
-
-/* Define to `int' if <sys/types.h> does not define. */
-#define EVENT__ssize_t SSIZE_T
-
-#endif
diff --git a/libs/libevent/src/WIN32-Code/tree.h b/libs/libevent/src/WIN32-Code/tree.h
deleted file mode 100644
index 2ccfbf20ac..0000000000
--- a/libs/libevent/src/WIN32-Code/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/libs/libevent/src/arc4random.cxx b/libs/libevent/src/arc4random.cxx
deleted file mode 100644
index 40d6642e58..0000000000
--- a/libs/libevent/src/arc4random.cxx
+++ /dev/null
@@ -1,556 +0,0 @@
-/* Portable arc4random.c based on arc4random.c from OpenBSD.
- * Portable version by Chris Davis, adapted for Libevent by Nick Mathewson
- * Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson
- * Copyright (c) 2010-2012 Niels Provos and Nick Mathewson
- *
- * Note that in Libevent, this file isn't compiled directly. Instead,
- * it's included from evutil_rand.c
- */
-
-/*
- * Copyright (c) 1996, David Mazieres <dm@uun.org>
- * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * Arc4 random number generator for OpenBSD.
- *
- * This code is derived from section 17.1 of Applied Cryptography,
- * second edition, which describes a stream cipher allegedly
- * compatible with RSA Labs "RC4" cipher (the actual description of
- * which is a trade secret). The same algorithm is used as a stream
- * cipher called "arcfour" in Tatu Ylonen's ssh package.
- *
- * Here the stream cipher has been modified always to include the time
- * when initializing the state. That makes it impossible to
- * regenerate the same random sequence twice, so this can't be used
- * for encryption, but will generate good random numbers.
- *
- * RC4 is a registered trademark of RSA Laboratories.
- */
-
-#ifndef ARC4RANDOM_EXPORT
-#define ARC4RANDOM_EXPORT
-#endif
-
-#ifndef ARC4RANDOM_UINT32
-#define ARC4RANDOM_UINT32 uint32_t
-#endif
-
-#ifndef ARC4RANDOM_NO_INCLUDES
-#include "evconfig-private.h"
-#ifdef _WIN32
-#include <Windows.h>
-#include <wincrypt.h>
-#include <process.h>
-#include <stdint.h>
-#else
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#ifdef EVENT__HAVE_SYS_SYSCTL_H
-#include <sys/sysctl.h>
-#endif
-#endif
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#endif
-
-/* Add platform entropy 32 bytes (256 bits) at a time. */
-#define ADD_ENTROPY 32
-
-/* Re-seed from the platform RNG after generating this many bytes. */
-#define BYTES_BEFORE_RESEED 1600000
-
-struct arc4_stream {
- unsigned char i;
- unsigned char j;
- unsigned char s[256];
-};
-
-#ifdef _WIN32
-#define getpid _getpid
-#define pid_t int
-#endif
-
-static int rs_initialized;
-static struct arc4_stream rs;
-static pid_t arc4_stir_pid;
-static int arc4_count;
-static int arc4_seeded_ok;
-
-static unsigned char arc4_getbyte(void);
-
-static void arc4_init(void)
-{
- int n;
-
- for (n = 0; n < 256; n++)
- rs.s[n] = n;
- rs.i = 0;
- rs.j = 0;
-}
-
-static void arc4_addrandom(const unsigned char *dat, int datlen)
-{
- int n;
- unsigned char si;
-
- rs.i--;
- for (n = 0; n < 256; n++) {
- rs.i = (rs.i + 1);
- si = rs.s[rs.i];
- rs.j = (rs.j + si + dat[n % datlen]);
- rs.s[rs.i] = rs.s[rs.j];
- rs.s[rs.j] = si;
- }
- rs.j = rs.i;
-}
-
-#ifndef _WIN32
-static ssize_t
-read_all(int fd, unsigned char *buf, size_t count)
-{
- size_t numread = 0;
- ssize_t result;
-
- while (numread < count) {
- result = read(fd, buf+numread, count-numread);
- if (result<0)
- return -1;
- else if (result == 0)
- break;
- numread += result;
- }
-
- return (ssize_t)numread;
-}
-#endif
-
-#ifdef _WIN32
-#define TRY_SEED_WIN32
-static int
-arc4_seed_win32(void)
-{
- /* This is adapted from Tor's crypto_seed_rng() */
- static int provider_set = 0;
- static HCRYPTPROV provider;
- unsigned char buf[ADD_ENTROPY];
-
- if (!provider_set) {
- if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
- return -1;
- }
- provider_set = 1;
- }
- if (!CryptGenRandom(provider, sizeof(buf), buf))
- return -1;
- arc4_addrandom(buf, sizeof(buf));
- evutil_memclear_(buf, sizeof(buf));
- arc4_seeded_ok = 1;
- return 0;
-}
-#endif
-
-#if defined(EVENT__HAVE_SYS_SYSCTL_H) && defined(EVENT__HAVE_SYSCTL)
-#if EVENT__HAVE_DECL_CTL_KERN && EVENT__HAVE_DECL_KERN_RANDOM && EVENT__HAVE_DECL_RANDOM_UUID
-#define TRY_SEED_SYSCTL_LINUX
-static int
-arc4_seed_sysctl_linux(void)
-{
- /* Based on code by William Ahern, this function tries to use the
- * RANDOM_UUID sysctl to get entropy from the kernel. This can work
- * even if /dev/urandom is inaccessible for some reason (e.g., we're
- * running in a chroot). */
- int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID };
- unsigned char buf[ADD_ENTROPY];
- size_t len, n;
- unsigned i;
- int any_set;
-
- memset(buf, 0, sizeof(buf));
-
- for (len = 0; len < sizeof(buf); len += n) {
- n = sizeof(buf) - len;
-
- if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0))
- return -1;
- }
- /* make sure that the buffer actually got set. */
- for (i=0,any_set=0; i<sizeof(buf); ++i) {
- any_set |= buf[i];
- }
- if (!any_set)
- return -1;
-
- arc4_addrandom(buf, sizeof(buf));
- evutil_memclear_(buf, sizeof(buf));
- arc4_seeded_ok = 1;
- return 0;
-}
-#endif
-
-#if EVENT__HAVE_DECL_CTL_KERN && EVENT__HAVE_DECL_KERN_ARND
-#define TRY_SEED_SYSCTL_BSD
-static int
-arc4_seed_sysctl_bsd(void)
-{
- /* Based on code from William Ahern and from OpenBSD, this function
- * tries to use the KERN_ARND syscall to get entropy from the kernel.
- * This can work even if /dev/urandom is inaccessible for some reason
- * (e.g., we're running in a chroot). */
- int mib[] = { CTL_KERN, KERN_ARND };
- unsigned char buf[ADD_ENTROPY];
- size_t len, n;
- int i, any_set;
-
- memset(buf, 0, sizeof(buf));
-
- len = sizeof(buf);
- if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
- for (len = 0; len < sizeof(buf); len += sizeof(unsigned)) {
- n = sizeof(unsigned);
- if (n + len > sizeof(buf))
- n = len - sizeof(buf);
- if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1)
- return -1;
- }
- }
- /* make sure that the buffer actually got set. */
- for (i=any_set=0; i<sizeof(buf); ++i) {
- any_set |= buf[i];
- }
- if (!any_set)
- return -1;
-
- arc4_addrandom(buf, sizeof(buf));
- evutil_memclear_(buf, sizeof(buf));
- arc4_seeded_ok = 1;
- return 0;
-}
-#endif
-#endif /* defined(EVENT__HAVE_SYS_SYSCTL_H) */
-
-#ifdef __linux__
-#define TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
-static int
-arc4_seed_proc_sys_kernel_random_uuid(void)
-{
- /* Occasionally, somebody will make /proc/sys accessible in a chroot,
- * but not /dev/urandom. Let's try /proc/sys/kernel/random/uuid.
- * Its format is stupid, so we need to decode it from hex.
- */
- int fd;
- char buf[128];
- unsigned char entropy[64];
- int bytes, n, i, nybbles;
- for (bytes = 0; bytes<ADD_ENTROPY; ) {
- fd = evutil_open_closeonexec_("/proc/sys/kernel/random/uuid", O_RDONLY, 0);
- if (fd < 0)
- return -1;
- n = read(fd, buf, sizeof(buf));
- close(fd);
- if (n<=0)
- return -1;
- memset(entropy, 0, sizeof(entropy));
- for (i=nybbles=0; i<n; ++i) {
- if (EVUTIL_ISXDIGIT_(buf[i])) {
- int nyb = evutil_hex_char_to_int_(buf[i]);
- if (nybbles & 1) {
- entropy[nybbles/2] |= nyb;
- } else {
- entropy[nybbles/2] |= nyb<<4;
- }
- ++nybbles;
- }
- }
- if (nybbles < 2)
- return -1;
- arc4_addrandom(entropy, nybbles/2);
- bytes += nybbles/2;
- }
- evutil_memclear_(entropy, sizeof(entropy));
- evutil_memclear_(buf, sizeof(buf));
- arc4_seeded_ok = 1;
- return 0;
-}
-#endif
-
-#ifndef _WIN32
-#define TRY_SEED_URANDOM
-static char *arc4random_urandom_filename = NULL;
-
-static int arc4_seed_urandom_helper_(const char *fname)
-{
- unsigned char buf[ADD_ENTROPY];
- int fd;
- size_t n;
-
- fd = evutil_open_closeonexec_(fname, O_RDONLY, 0);
- if (fd<0)
- return -1;
- n = read_all(fd, buf, sizeof(buf));
- close(fd);
- if (n != sizeof(buf))
- return -1;
- arc4_addrandom(buf, sizeof(buf));
- evutil_memclear_(buf, sizeof(buf));
- arc4_seeded_ok = 1;
- return 0;
-}
-
-static int
-arc4_seed_urandom(void)
-{
- /* This is adapted from Tor's crypto_seed_rng() */
- static const char *filenames[] = {
- "/dev/srandom", "/dev/urandom", "/dev/random", NULL
- };
- int i;
- if (arc4random_urandom_filename)
- return arc4_seed_urandom_helper_(arc4random_urandom_filename);
-
- for (i = 0; filenames[i]; ++i) {
- if (arc4_seed_urandom_helper_(filenames[i]) == 0) {
- return 0;
- }
- }
-
- return -1;
-}
-#endif
-
-static int
-arc4_seed(void)
-{
- int ok = 0;
- /* We try every method that might work, and don't give up even if one
- * does seem to work. There's no real harm in over-seeding, and if
- * one of these sources turns out to be broken, that would be bad. */
-#ifdef TRY_SEED_WIN32
- if (0 == arc4_seed_win32())
- ok = 1;
-#endif
-#ifdef TRY_SEED_URANDOM
- if (0 == arc4_seed_urandom())
- ok = 1;
-#endif
-#ifdef TRY_SEED_PROC_SYS_KERNEL_RANDOM_UUID
- if (arc4random_urandom_filename == NULL &&
- 0 == arc4_seed_proc_sys_kernel_random_uuid())
- ok = 1;
-#endif
-#ifdef TRY_SEED_SYSCTL_LINUX
- /* Apparently Linux is deprecating sysctl, and spewing warning
- * messages when you try to use it. */
- if (!ok && 0 == arc4_seed_sysctl_linux())
- ok = 1;
-#endif
-#ifdef TRY_SEED_SYSCTL_BSD
- if (0 == arc4_seed_sysctl_bsd())
- ok = 1;
-#endif
- return ok ? 0 : -1;
-}
-
-static int
-arc4_stir(void)
-{
- int i;
-
- if (!rs_initialized) {
- arc4_init();
- rs_initialized = 1;
- }
-
- arc4_seed();
- if (!arc4_seeded_ok)
- return -1;
-
- /*
- * Discard early keystream, as per recommendations in
- * "Weaknesses in the Key Scheduling Algorithm of RC4" by
- * Scott Fluhrer, Itsik Mantin, and Adi Shamir.
- * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
- *
- * Ilya Mironov's "(Not So) Random Shuffles of RC4" suggests that
- * we drop at least 2*256 bytes, with 12*256 as a conservative
- * value.
- *
- * RFC4345 says to drop 6*256.
- *
- * At least some versions of this code drop 4*256, in a mistaken
- * belief that "words" in the Fluhrer/Mantin/Shamir paper refers
- * to processor words.
- *
- * We add another sect to the cargo cult, and choose 12*256.
- */
- for (i = 0; i < 12*256; i++)
- (void)arc4_getbyte();
-
- arc4_count = BYTES_BEFORE_RESEED;
-
- return 0;
-}
-
-
-static void
-arc4_stir_if_needed(void)
-{
- pid_t pid = getpid();
-
- if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid)
- {
- arc4_stir_pid = pid;
- arc4_stir();
- }
-}
-
-static unsigned char
-arc4_getbyte(void)
-{
- unsigned char si, sj;
-
- rs.i = (rs.i + 1);
- si = rs.s[rs.i];
- rs.j = (rs.j + si);
- sj = rs.s[rs.j];
- rs.s[rs.i] = sj;
- rs.s[rs.j] = si;
- return (rs.s[(si + sj) & 0xff]);
-}
-
-static unsigned int
-arc4_getword(void)
-{
- unsigned int val;
-
- val = arc4_getbyte() << 24;
- val |= arc4_getbyte() << 16;
- val |= arc4_getbyte() << 8;
- val |= arc4_getbyte();
-
- return val;
-}
-
-#ifndef ARC4RANDOM_NOSTIR
-ARC4RANDOM_EXPORT int
-arc4random_stir(void)
-{
- int val;
- ARC4_LOCK_();
- val = arc4_stir();
- ARC4_UNLOCK_();
- return val;
-}
-#endif
-
-#ifndef ARC4RANDOM_NOADDRANDOM
-ARC4RANDOM_EXPORT void
-arc4random_addrandom(const unsigned char *dat, int datlen)
-{
- int j;
- ARC4_LOCK_();
- if (!rs_initialized)
- arc4_stir();
- for (j = 0; j < datlen; j += 256) {
- /* arc4_addrandom() ignores all but the first 256 bytes of
- * its input. We want to make sure to look at ALL the
- * data in 'dat', just in case the user is doing something
- * crazy like passing us all the files in /var/log. */
- arc4_addrandom(dat + j, datlen - j);
- }
- ARC4_UNLOCK_();
-}
-#endif
-
-#ifndef ARC4RANDOM_NORANDOM
-ARC4RANDOM_EXPORT ARC4RANDOM_UINT32
-arc4random(void)
-{
- ARC4RANDOM_UINT32 val;
- ARC4_LOCK_();
- arc4_count -= 4;
- arc4_stir_if_needed();
- val = arc4_getword();
- ARC4_UNLOCK_();
- return val;
-}
-#endif
-
-ARC4RANDOM_EXPORT void
-arc4random_buf(void *buf_, size_t n)
-{
- unsigned char *buf = buf_;
- ARC4_LOCK_();
- arc4_stir_if_needed();
- while (n--) {
- if (--arc4_count <= 0)
- arc4_stir();
- buf[n] = arc4_getbyte();
- }
- ARC4_UNLOCK_();
-}
-
-#ifndef ARC4RANDOM_NOUNIFORM
-/*
- * Calculate a uniformly distributed random number less than upper_bound
- * avoiding "modulo bias".
- *
- * Uniformity is achieved by generating new random numbers until the one
- * returned is outside the range [0, 2**32 % upper_bound). This
- * guarantees the selected random number will be inside
- * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
- * after reduction modulo upper_bound.
- */
-ARC4RANDOM_EXPORT unsigned int
-arc4random_uniform(unsigned int upper_bound)
-{
- ARC4RANDOM_UINT32 r, min;
-
- if (upper_bound < 2)
- return 0;
-
-#if (UINT_MAX > 0xffffffffUL)
- min = 0x100000000UL % upper_bound;
-#else
- /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
- if (upper_bound > 0x80000000)
- min = 1 + ~upper_bound; /* 2**32 - upper_bound */
- else {
- /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
- min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
- }
-#endif
-
- /*
- * This could theoretically loop forever but each retry has
- * p > 0.5 (worst case, usually far better) of selecting a
- * number inside the range we need, so it should rarely need
- * to re-roll.
- */
- for (;;) {
- r = arc4random();
- if (r >= min)
- break;
- }
-
- return r % upper_bound;
-}
-#endif
diff --git a/libs/libevent/src/buffer.c b/libs/libevent/src/buffer.c
deleted file mode 100644
index 7cca0e8a7d..0000000000
--- a/libs/libevent/src/buffer.c
+++ /dev/null
@@ -1,3439 +0,0 @@
-/*
- * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <windows.h>
-#include <io.h>
-#endif
-
-#ifdef EVENT__HAVE_VASPRINTF
-/* If we have vasprintf, we need to define _GNU_SOURCE before we include
- * stdio.h. This comes from evconfig-private.h.
- */
-#endif
-
-#include <sys/types.h>
-
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#ifdef EVENT__HAVE_SYS_UIO_H
-#include <sys/uio.h>
-#endif
-
-#ifdef EVENT__HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#ifdef EVENT__HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-#ifdef EVENT__HAVE_SYS_SENDFILE_H
-#include <sys/sendfile.h>
-#endif
-#ifdef EVENT__HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <limits.h>
-
-#include "event2/event.h"
-#include "event2/buffer.h"
-#include "event2/buffer_compat.h"
-#include "event2/bufferevent.h"
-#include "event2/bufferevent_compat.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/thread.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "util-internal.h"
-#include "evthread-internal.h"
-#include "evbuffer-internal.h"
-#include "bufferevent-internal.h"
-
-/* some systems do not have MAP_FAILED */
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *)-1)
-#endif
-
-/* send file support */
-#if defined(EVENT__HAVE_SYS_SENDFILE_H) && defined(EVENT__HAVE_SENDFILE) && defined(__linux__)
-#define USE_SENDFILE 1
-#define SENDFILE_IS_LINUX 1
-#elif defined(EVENT__HAVE_SENDFILE) && defined(__FreeBSD__)
-#define USE_SENDFILE 1
-#define SENDFILE_IS_FREEBSD 1
-#elif defined(EVENT__HAVE_SENDFILE) && defined(__APPLE__)
-#define USE_SENDFILE 1
-#define SENDFILE_IS_MACOSX 1
-#elif defined(EVENT__HAVE_SENDFILE) && defined(__sun__) && defined(__svr4__)
-#define USE_SENDFILE 1
-#define SENDFILE_IS_SOLARIS 1
-#endif
-
-/* Mask of user-selectable callback flags. */
-#define EVBUFFER_CB_USER_FLAGS 0xffff
-/* Mask of all internal-use-only flags. */
-#define EVBUFFER_CB_INTERNAL_FLAGS 0xffff0000
-
-/* Flag set if the callback is using the cb_obsolete function pointer */
-#define EVBUFFER_CB_OBSOLETE 0x00040000
-
-/* evbuffer_chain support */
-#define CHAIN_SPACE_PTR(ch) ((ch)->buffer + (ch)->misalign + (ch)->off)
-#define CHAIN_SPACE_LEN(ch) ((ch)->flags & EVBUFFER_IMMUTABLE ? \
- 0 : (ch)->buffer_len - ((ch)->misalign + (ch)->off))
-
-#define CHAIN_PINNED(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_ANY) != 0)
-#define CHAIN_PINNED_R(ch) (((ch)->flags & EVBUFFER_MEM_PINNED_R) != 0)
-
-/* evbuffer_ptr support */
-#define PTR_NOT_FOUND(ptr) do { \
- (ptr)->pos = -1; \
- (ptr)->internal_.chain = NULL; \
- (ptr)->internal_.pos_in_chain = 0; \
-} while (0)
-
-static void evbuffer_chain_align(struct evbuffer_chain *chain);
-static int evbuffer_chain_should_realign(struct evbuffer_chain *chain,
- size_t datalen);
-static void evbuffer_deferred_callback(struct event_callback *cb, void *arg);
-static int evbuffer_ptr_memcmp(const struct evbuffer *buf,
- const struct evbuffer_ptr *pos, const char *mem, size_t len);
-static struct evbuffer_chain *evbuffer_expand_singlechain(struct evbuffer *buf,
- size_t datlen);
-static int evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
- size_t howfar);
-static int evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg);
-static inline void evbuffer_chain_incref(struct evbuffer_chain *chain);
-
-static struct evbuffer_chain *
-evbuffer_chain_new(size_t size)
-{
- struct evbuffer_chain *chain;
- size_t to_alloc;
-
- if (size > EVBUFFER_CHAIN_MAX - EVBUFFER_CHAIN_SIZE)
- return (NULL);
-
- size += EVBUFFER_CHAIN_SIZE;
-
- /* get the next largest memory that can hold the buffer */
- if (size < EVBUFFER_CHAIN_MAX / 2) {
- to_alloc = MIN_BUFFER_SIZE;
- while (to_alloc < size) {
- to_alloc <<= 1;
- }
- } else {
- to_alloc = size;
- }
-
- /* we get everything in one chunk */
- if ((chain = mm_malloc(to_alloc)) == NULL)
- return (NULL);
-
- memset(chain, 0, EVBUFFER_CHAIN_SIZE);
-
- chain->buffer_len = to_alloc - EVBUFFER_CHAIN_SIZE;
-
- /* this way we can manipulate the buffer to different addresses,
- * which is required for mmap for example.
- */
- chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);
-
- chain->refcnt = 1;
-
- return (chain);
-}
-
-static inline void
-evbuffer_chain_free(struct evbuffer_chain *chain)
-{
- EVUTIL_ASSERT(chain->refcnt > 0);
- if (--chain->refcnt > 0) {
- /* chain is still referenced by other chains */
- return;
- }
-
- if (CHAIN_PINNED(chain)) {
- /* will get freed once no longer dangling */
- chain->refcnt++;
- chain->flags |= EVBUFFER_DANGLING;
- return;
- }
-
- /* safe to release chain, it's either a referencing
- * chain or all references to it have been freed */
- if (chain->flags & EVBUFFER_REFERENCE) {
- struct evbuffer_chain_reference *info =
- EVBUFFER_CHAIN_EXTRA(
- struct evbuffer_chain_reference,
- chain);
- if (info->cleanupfn)
- (*info->cleanupfn)(chain->buffer,
- chain->buffer_len,
- info->extra);
- }
- if (chain->flags & EVBUFFER_FILESEGMENT) {
- struct evbuffer_chain_file_segment *info =
- EVBUFFER_CHAIN_EXTRA(
- struct evbuffer_chain_file_segment,
- chain);
- if (info->segment) {
-#ifdef _WIN32
- if (info->segment->is_mapping)
- UnmapViewOfFile(chain->buffer);
-#endif
- evbuffer_file_segment_free(info->segment);
- }
- }
- if (chain->flags & EVBUFFER_MULTICAST) {
- struct evbuffer_multicast_parent *info =
- EVBUFFER_CHAIN_EXTRA(
- struct evbuffer_multicast_parent,
- chain);
- /* referencing chain is being freed, decrease
- * refcounts of source chain and associated
- * evbuffer (which get freed once both reach
- * zero) */
- EVUTIL_ASSERT(info->source != NULL);
- EVUTIL_ASSERT(info->parent != NULL);
- EVBUFFER_LOCK(info->source);
- evbuffer_chain_free(info->parent);
- evbuffer_decref_and_unlock_(info->source);
- }
-
- mm_free(chain);
-}
-
-static void
-evbuffer_free_all_chains(struct evbuffer_chain *chain)
-{
- struct evbuffer_chain *next;
- for (; chain; chain = next) {
- next = chain->next;
- evbuffer_chain_free(chain);
- }
-}
-
-#ifndef NDEBUG
-static int
-evbuffer_chains_all_empty(struct evbuffer_chain *chain)
-{
- for (; chain; chain = chain->next) {
- if (chain->off)
- return 0;
- }
- return 1;
-}
-#else
-/* The definition is needed for EVUTIL_ASSERT, which uses sizeof to avoid
-"unused variable" warnings. */
-static inline int evbuffer_chains_all_empty(struct evbuffer_chain *chain) {
- return 1;
-}
-#endif
-
-/* Free all trailing chains in 'buf' that are neither pinned nor empty, prior
- * to replacing them all with a new chain. Return a pointer to the place
- * where the new chain will go.
- *
- * Internal; requires lock. The caller must fix up buf->last and buf->first
- * as needed; they might have been freed.
- */
-static struct evbuffer_chain **
-evbuffer_free_trailing_empty_chains(struct evbuffer *buf)
-{
- struct evbuffer_chain **ch = buf->last_with_datap;
- /* Find the first victim chain. It might be *last_with_datap */
- while ((*ch) && ((*ch)->off != 0 || CHAIN_PINNED(*ch)))
- ch = &(*ch)->next;
- if (*ch) {
- EVUTIL_ASSERT(evbuffer_chains_all_empty(*ch));
- evbuffer_free_all_chains(*ch);
- *ch = NULL;
- }
- return ch;
-}
-
-/* Add a single chain 'chain' to the end of 'buf', freeing trailing empty
- * chains as necessary. Requires lock. Does not schedule callbacks.
- */
-static void
-evbuffer_chain_insert(struct evbuffer *buf,
- struct evbuffer_chain *chain)
-{
- ASSERT_EVBUFFER_LOCKED(buf);
- if (*buf->last_with_datap == NULL) {
- /* There are no chains data on the buffer at all. */
- EVUTIL_ASSERT(buf->last_with_datap == &buf->first);
- EVUTIL_ASSERT(buf->first == NULL);
- buf->first = buf->last = chain;
- } else {
- struct evbuffer_chain **chp;
- chp = evbuffer_free_trailing_empty_chains(buf);
- *chp = chain;
- if (chain->off)
- buf->last_with_datap = chp;
- buf->last = chain;
- }
- buf->total_len += chain->off;
-}
-
-static inline struct evbuffer_chain *
-evbuffer_chain_insert_new(struct evbuffer *buf, size_t datlen)
-{
- struct evbuffer_chain *chain;
- if ((chain = evbuffer_chain_new(datlen)) == NULL)
- return NULL;
- evbuffer_chain_insert(buf, chain);
- return chain;
-}
-
-void
-evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag)
-{
- EVUTIL_ASSERT((chain->flags & flag) == 0);
- chain->flags |= flag;
-}
-
-void
-evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag)
-{
- EVUTIL_ASSERT((chain->flags & flag) != 0);
- chain->flags &= ~flag;
- if (chain->flags & EVBUFFER_DANGLING)
- evbuffer_chain_free(chain);
-}
-
-static inline void
-evbuffer_chain_incref(struct evbuffer_chain *chain)
-{
- ++chain->refcnt;
-}
-
-struct evbuffer *
-evbuffer_new(void)
-{
- struct evbuffer *buffer;
-
- buffer = mm_calloc(1, sizeof(struct evbuffer));
- if (buffer == NULL)
- return (NULL);
-
- LIST_INIT(&buffer->callbacks);
- buffer->refcnt = 1;
- buffer->last_with_datap = &buffer->first;
-
- return (buffer);
-}
-
-int
-evbuffer_set_flags(struct evbuffer *buf, ev_uint64_t flags)
-{
- EVBUFFER_LOCK(buf);
- buf->flags |= (ev_uint32_t)flags;
- EVBUFFER_UNLOCK(buf);
- return 0;
-}
-
-int
-evbuffer_clear_flags(struct evbuffer *buf, ev_uint64_t flags)
-{
- EVBUFFER_LOCK(buf);
- buf->flags &= ~(ev_uint32_t)flags;
- EVBUFFER_UNLOCK(buf);
- return 0;
-}
-
-void
-evbuffer_incref_(struct evbuffer *buf)
-{
- EVBUFFER_LOCK(buf);
- ++buf->refcnt;
- EVBUFFER_UNLOCK(buf);
-}
-
-void
-evbuffer_incref_and_lock_(struct evbuffer *buf)
-{
- EVBUFFER_LOCK(buf);
- ++buf->refcnt;
-}
-
-int
-evbuffer_defer_callbacks(struct evbuffer *buffer, struct event_base *base)
-{
- EVBUFFER_LOCK(buffer);
- buffer->cb_queue = base;
- buffer->deferred_cbs = 1;
- event_deferred_cb_init_(&buffer->deferred,
- event_base_get_npriorities(base) / 2,
- evbuffer_deferred_callback, buffer);
- EVBUFFER_UNLOCK(buffer);
- return 0;
-}
-
-int
-evbuffer_enable_locking(struct evbuffer *buf, void *lock)
-{
-#ifdef EVENT__DISABLE_THREAD_SUPPORT
- return -1;
-#else
- if (buf->lock)
- return -1;
-
- if (!lock) {
- EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- if (!lock)
- return -1;
- buf->lock = lock;
- buf->own_lock = 1;
- } else {
- buf->lock = lock;
- buf->own_lock = 0;
- }
-
- return 0;
-#endif
-}
-
-void
-evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev)
-{
- EVBUFFER_LOCK(buf);
- buf->parent = bev;
- EVBUFFER_UNLOCK(buf);
-}
-
-static void
-evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred)
-{
- struct evbuffer_cb_entry *cbent, *next;
- struct evbuffer_cb_info info;
- size_t new_size;
- ev_uint32_t mask, masked_val;
- int clear = 1;
-
- if (running_deferred) {
- mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
- masked_val = EVBUFFER_CB_ENABLED;
- } else if (buffer->deferred_cbs) {
- mask = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
- masked_val = EVBUFFER_CB_NODEFER|EVBUFFER_CB_ENABLED;
- /* Don't zero-out n_add/n_del, since the deferred callbacks
- will want to see them. */
- clear = 0;
- } else {
- mask = EVBUFFER_CB_ENABLED;
- masked_val = EVBUFFER_CB_ENABLED;
- }
-
- ASSERT_EVBUFFER_LOCKED(buffer);
-
- if (LIST_EMPTY(&buffer->callbacks)) {
- buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
- return;
- }
- if (buffer->n_add_for_cb == 0 && buffer->n_del_for_cb == 0)
- return;
-
- new_size = buffer->total_len;
- info.orig_size = new_size + buffer->n_del_for_cb - buffer->n_add_for_cb;
- info.n_added = buffer->n_add_for_cb;
- info.n_deleted = buffer->n_del_for_cb;
- if (clear) {
- buffer->n_add_for_cb = 0;
- buffer->n_del_for_cb = 0;
- }
- for (cbent = LIST_FIRST(&buffer->callbacks);
- cbent != LIST_END(&buffer->callbacks);
- cbent = next) {
- /* Get the 'next' pointer now in case this callback decides
- * to remove itself or something. */
- next = LIST_NEXT(cbent, next);
-
- if ((cbent->flags & mask) != masked_val)
- continue;
-
- if ((cbent->flags & EVBUFFER_CB_OBSOLETE))
- cbent->cb.cb_obsolete(buffer,
- info.orig_size, new_size, cbent->cbarg);
- else
- cbent->cb.cb_func(buffer, &info, cbent->cbarg);
- }
-}
-
-void
-evbuffer_invoke_callbacks_(struct evbuffer *buffer)
-{
- if (LIST_EMPTY(&buffer->callbacks)) {
- buffer->n_add_for_cb = buffer->n_del_for_cb = 0;
- return;
- }
-
- if (buffer->deferred_cbs) {
- if (event_deferred_cb_schedule_(buffer->cb_queue, &buffer->deferred)) {
- evbuffer_incref_and_lock_(buffer);
- if (buffer->parent)
- bufferevent_incref_(buffer->parent);
- }
- EVBUFFER_UNLOCK(buffer);
- }
-
- evbuffer_run_callbacks(buffer, 0);
-}
-
-static void
-evbuffer_deferred_callback(struct event_callback *cb, void *arg)
-{
- struct bufferevent *parent = NULL;
- struct evbuffer *buffer = arg;
-
- /* XXXX It would be better to run these callbacks without holding the
- * lock */
- EVBUFFER_LOCK(buffer);
- parent = buffer->parent;
- evbuffer_run_callbacks(buffer, 1);
- evbuffer_decref_and_unlock_(buffer);
- if (parent)
- bufferevent_decref_(parent);
-}
-
-static void
-evbuffer_remove_all_callbacks(struct evbuffer *buffer)
-{
- struct evbuffer_cb_entry *cbent;
-
- while ((cbent = LIST_FIRST(&buffer->callbacks))) {
- LIST_REMOVE(cbent, next);
- mm_free(cbent);
- }
-}
-
-void
-evbuffer_decref_and_unlock_(struct evbuffer *buffer)
-{
- struct evbuffer_chain *chain, *next;
- ASSERT_EVBUFFER_LOCKED(buffer);
-
- EVUTIL_ASSERT(buffer->refcnt > 0);
-
- if (--buffer->refcnt > 0) {
- EVBUFFER_UNLOCK(buffer);
- return;
- }
-
- for (chain = buffer->first; chain != NULL; chain = next) {
- next = chain->next;
- evbuffer_chain_free(chain);
- }
- evbuffer_remove_all_callbacks(buffer);
- if (buffer->deferred_cbs)
- event_deferred_cb_cancel_(buffer->cb_queue, &buffer->deferred);
-
- EVBUFFER_UNLOCK(buffer);
- if (buffer->own_lock)
- EVTHREAD_FREE_LOCK(buffer->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- mm_free(buffer);
-}
-
-void
-evbuffer_free(struct evbuffer *buffer)
-{
- EVBUFFER_LOCK(buffer);
- evbuffer_decref_and_unlock_(buffer);
-}
-
-void
-evbuffer_lock(struct evbuffer *buf)
-{
- EVBUFFER_LOCK(buf);
-}
-
-void
-evbuffer_unlock(struct evbuffer *buf)
-{
- EVBUFFER_UNLOCK(buf);
-}
-
-size_t
-evbuffer_get_length(const struct evbuffer *buffer)
-{
- size_t result;
-
- EVBUFFER_LOCK(buffer);
-
- result = (buffer->total_len);
-
- EVBUFFER_UNLOCK(buffer);
-
- return result;
-}
-
-size_t
-evbuffer_get_contiguous_space(const struct evbuffer *buf)
-{
- struct evbuffer_chain *chain;
- size_t result;
-
- EVBUFFER_LOCK(buf);
- chain = buf->first;
- result = (chain != NULL ? chain->off : 0);
- EVBUFFER_UNLOCK(buf);
-
- return result;
-}
-
-size_t
-evbuffer_add_iovec(struct evbuffer * buf, struct evbuffer_iovec * vec, int n_vec) {
- int n;
- size_t res;
- size_t to_alloc;
-
- EVBUFFER_LOCK(buf);
-
- res = to_alloc = 0;
-
- for (n = 0; n < n_vec; n++) {
- to_alloc += vec[n].iov_len;
- }
-
- if (evbuffer_expand_fast_(buf, to_alloc, 2) < 0) {
- goto done;
- }
-
- for (n = 0; n < n_vec; n++) {
- /* XXX each 'add' call here does a bunch of setup that's
- * obviated by evbuffer_expand_fast_, and some cleanup that we
- * would like to do only once. Instead we should just extract
- * the part of the code that's needed. */
-
- if (evbuffer_add(buf, vec[n].iov_base, vec[n].iov_len) < 0) {
- goto done;
- }
-
- res += vec[n].iov_len;
- }
-
-done:
- EVBUFFER_UNLOCK(buf);
- return res;
-}
-
-int
-evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
- struct evbuffer_iovec *vec, int n_vecs)
-{
- struct evbuffer_chain *chain, **chainp;
- int n = -1;
-
- EVBUFFER_LOCK(buf);
- if (buf->freeze_end)
- goto done;
- if (n_vecs < 1)
- goto done;
- if (n_vecs == 1) {
- if ((chain = evbuffer_expand_singlechain(buf, size)) == NULL)
- goto done;
-
- vec[0].iov_base = CHAIN_SPACE_PTR(chain);
- vec[0].iov_len = (size_t) CHAIN_SPACE_LEN(chain);
- EVUTIL_ASSERT(size<0 || (size_t)vec[0].iov_len >= (size_t)size);
- n = 1;
- } else {
- if (evbuffer_expand_fast_(buf, size, n_vecs)<0)
- goto done;
- n = evbuffer_read_setup_vecs_(buf, size, vec, n_vecs,
- &chainp, 0);
- }
-
-done:
- EVBUFFER_UNLOCK(buf);
- return n;
-
-}
-
-static int
-advance_last_with_data(struct evbuffer *buf)
-{
- int n = 0;
- ASSERT_EVBUFFER_LOCKED(buf);
-
- if (!*buf->last_with_datap)
- return 0;
-
- while ((*buf->last_with_datap)->next && (*buf->last_with_datap)->next->off) {
- buf->last_with_datap = &(*buf->last_with_datap)->next;
- ++n;
- }
- return n;
-}
-
-int
-evbuffer_commit_space(struct evbuffer *buf,
- struct evbuffer_iovec *vec, int n_vecs)
-{
- struct evbuffer_chain *chain, **firstchainp, **chainp;
- int result = -1;
- size_t added = 0;
- int i;
-
- EVBUFFER_LOCK(buf);
-
- if (buf->freeze_end)
- goto done;
- if (n_vecs == 0) {
- result = 0;
- goto done;
- } else if (n_vecs == 1 &&
- (buf->last && vec[0].iov_base == (void*)CHAIN_SPACE_PTR(buf->last))) {
- /* The user only got or used one chain; it might not
- * be the first one with space in it. */
- if ((size_t)vec[0].iov_len > (size_t)CHAIN_SPACE_LEN(buf->last))
- goto done;
- buf->last->off += vec[0].iov_len;
- added = vec[0].iov_len;
- if (added)
- advance_last_with_data(buf);
- goto okay;
- }
-
- /* Advance 'firstchain' to the first chain with space in it. */
- firstchainp = buf->last_with_datap;
- if (!*firstchainp)
- goto done;
- if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
- firstchainp = &(*firstchainp)->next;
- }
-
- chain = *firstchainp;
- /* pass 1: make sure that the pointers and lengths of vecs[] are in
- * bounds before we try to commit anything. */
- for (i=0; i<n_vecs; ++i) {
- if (!chain)
- goto done;
- if (vec[i].iov_base != (void*)CHAIN_SPACE_PTR(chain) ||
- (size_t)vec[i].iov_len > CHAIN_SPACE_LEN(chain))
- goto done;
- chain = chain->next;
- }
- /* pass 2: actually adjust all the chains. */
- chainp = firstchainp;
- for (i=0; i<n_vecs; ++i) {
- (*chainp)->off += vec[i].iov_len;
- added += vec[i].iov_len;
- if (vec[i].iov_len) {
- buf->last_with_datap = chainp;
- }
- chainp = &(*chainp)->next;
- }
-
-okay:
- buf->total_len += added;
- buf->n_add_for_cb += added;
- result = 0;
- evbuffer_invoke_callbacks_(buf);
-
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-static inline int
-HAS_PINNED_R(struct evbuffer *buf)
-{
- return (buf->last && CHAIN_PINNED_R(buf->last));
-}
-
-static inline void
-ZERO_CHAIN(struct evbuffer *dst)
-{
- ASSERT_EVBUFFER_LOCKED(dst);
- dst->first = NULL;
- dst->last = NULL;
- dst->last_with_datap = &(dst)->first;
- dst->total_len = 0;
-}
-
-/* Prepares the contents of src to be moved to another buffer by removing
- * read-pinned chains. The first pinned chain is saved in first, and the
- * last in last. If src has no read-pinned chains, first and last are set
- * to NULL. */
-static int
-PRESERVE_PINNED(struct evbuffer *src, struct evbuffer_chain **first,
- struct evbuffer_chain **last)
-{
- struct evbuffer_chain *chain, **pinned;
-
- ASSERT_EVBUFFER_LOCKED(src);
-
- if (!HAS_PINNED_R(src)) {
- *first = *last = NULL;
- return 0;
- }
-
- pinned = src->last_with_datap;
- if (!CHAIN_PINNED_R(*pinned))
- pinned = &(*pinned)->next;
- EVUTIL_ASSERT(CHAIN_PINNED_R(*pinned));
- chain = *first = *pinned;
- *last = src->last;
-
- /* If there's data in the first pinned chain, we need to allocate
- * a new chain and copy the data over. */
- if (chain->off) {
- struct evbuffer_chain *tmp;
-
- EVUTIL_ASSERT(pinned == src->last_with_datap);
- tmp = evbuffer_chain_new(chain->off);
- if (!tmp)
- return -1;
- memcpy(tmp->buffer, chain->buffer + chain->misalign,
- chain->off);
- tmp->off = chain->off;
- *src->last_with_datap = tmp;
- src->last = tmp;
- chain->misalign += chain->off;
- chain->off = 0;
- } else {
- src->last = *src->last_with_datap;
- *pinned = NULL;
- }
-
- return 0;
-}
-
-static inline void
-RESTORE_PINNED(struct evbuffer *src, struct evbuffer_chain *pinned,
- struct evbuffer_chain *last)
-{
- ASSERT_EVBUFFER_LOCKED(src);
-
- if (!pinned) {
- ZERO_CHAIN(src);
- return;
- }
-
- src->first = pinned;
- src->last = last;
- src->last_with_datap = &src->first;
- src->total_len = 0;
-}
-
-static inline void
-COPY_CHAIN(struct evbuffer *dst, struct evbuffer *src)
-{
- ASSERT_EVBUFFER_LOCKED(dst);
- ASSERT_EVBUFFER_LOCKED(src);
- dst->first = src->first;
- if (src->last_with_datap == &src->first)
- dst->last_with_datap = &dst->first;
- else
- dst->last_with_datap = src->last_with_datap;
- dst->last = src->last;
- dst->total_len = src->total_len;
-}
-
-static void
-APPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
-{
- ASSERT_EVBUFFER_LOCKED(dst);
- ASSERT_EVBUFFER_LOCKED(src);
- dst->last->next = src->first;
- if (src->last_with_datap == &src->first)
- dst->last_with_datap = &dst->last->next;
- else
- dst->last_with_datap = src->last_with_datap;
- dst->last = src->last;
- dst->total_len += src->total_len;
-}
-
-static inline void
-APPEND_CHAIN_MULTICAST(struct evbuffer *dst, struct evbuffer *src)
-{
- struct evbuffer_chain *tmp;
- struct evbuffer_chain *chain = src->first;
- struct evbuffer_multicast_parent *extra;
-
- ASSERT_EVBUFFER_LOCKED(dst);
- ASSERT_EVBUFFER_LOCKED(src);
-
- for (; chain; chain = chain->next) {
- if (!chain->off || chain->flags & EVBUFFER_DANGLING) {
- /* skip empty chains */
- continue;
- }
-
- tmp = evbuffer_chain_new(sizeof(struct evbuffer_multicast_parent));
- if (!tmp) {
- event_warn("%s: out of memory", __func__);
- return;
- }
- extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
- /* reference evbuffer containing source chain so it
- * doesn't get released while the chain is still
- * being referenced to */
- evbuffer_incref_(src);
- extra->source = src;
- /* reference source chain which now becomes immutable */
- evbuffer_chain_incref(chain);
- extra->parent = chain;
- chain->flags |= EVBUFFER_IMMUTABLE;
- tmp->buffer_len = chain->buffer_len;
- tmp->misalign = chain->misalign;
- tmp->off = chain->off;
- tmp->flags |= EVBUFFER_MULTICAST|EVBUFFER_IMMUTABLE;
- tmp->buffer = chain->buffer;
- evbuffer_chain_insert(dst, tmp);
- }
-}
-
-static void
-PREPEND_CHAIN(struct evbuffer *dst, struct evbuffer *src)
-{
- ASSERT_EVBUFFER_LOCKED(dst);
- ASSERT_EVBUFFER_LOCKED(src);
- src->last->next = dst->first;
- dst->first = src->first;
- dst->total_len += src->total_len;
- if (*dst->last_with_datap == NULL) {
- if (src->last_with_datap == &(src)->first)
- dst->last_with_datap = &dst->first;
- else
- dst->last_with_datap = src->last_with_datap;
- } else if (dst->last_with_datap == &dst->first) {
- dst->last_with_datap = &src->last->next;
- }
-}
-
-int
-evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
-{
- struct evbuffer_chain *pinned, *last;
- size_t in_total_len, out_total_len;
- int result = 0;
-
- EVBUFFER_LOCK2(inbuf, outbuf);
- in_total_len = inbuf->total_len;
- out_total_len = outbuf->total_len;
-
- if (in_total_len == 0 || outbuf == inbuf)
- goto done;
-
- if (outbuf->freeze_end || inbuf->freeze_start) {
- result = -1;
- goto done;
- }
-
- if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
- result = -1;
- goto done;
- }
-
- if (out_total_len == 0) {
- /* There might be an empty chain at the start of outbuf; free
- * it. */
- evbuffer_free_all_chains(outbuf->first);
- COPY_CHAIN(outbuf, inbuf);
- } else {
- APPEND_CHAIN(outbuf, inbuf);
- }
-
- RESTORE_PINNED(inbuf, pinned, last);
-
- inbuf->n_del_for_cb += in_total_len;
- outbuf->n_add_for_cb += in_total_len;
-
- evbuffer_invoke_callbacks_(inbuf);
- evbuffer_invoke_callbacks_(outbuf);
-
-done:
- EVBUFFER_UNLOCK2(inbuf, outbuf);
- return result;
-}
-
-int
-evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)
-{
- size_t in_total_len, out_total_len;
- struct evbuffer_chain *chain;
- int result = 0;
-
- EVBUFFER_LOCK2(inbuf, outbuf);
- in_total_len = inbuf->total_len;
- out_total_len = outbuf->total_len;
- chain = inbuf->first;
-
- if (in_total_len == 0)
- goto done;
-
- if (outbuf->freeze_end || outbuf == inbuf) {
- result = -1;
- goto done;
- }
-
- for (; chain; chain = chain->next) {
- if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE|EVBUFFER_MULTICAST)) != 0) {
- /* chain type can not be referenced */
- result = -1;
- goto done;
- }
- }
-
- if (out_total_len == 0) {
- /* There might be an empty chain at the start of outbuf; free
- * it. */
- evbuffer_free_all_chains(outbuf->first);
- }
- APPEND_CHAIN_MULTICAST(outbuf, inbuf);
-
- outbuf->n_add_for_cb += in_total_len;
- evbuffer_invoke_callbacks_(outbuf);
-
-done:
- EVBUFFER_UNLOCK2(inbuf, outbuf);
- return result;
-}
-
-int
-evbuffer_prepend_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
-{
- struct evbuffer_chain *pinned, *last;
- size_t in_total_len, out_total_len;
- int result = 0;
-
- EVBUFFER_LOCK2(inbuf, outbuf);
-
- in_total_len = inbuf->total_len;
- out_total_len = outbuf->total_len;
-
- if (!in_total_len || inbuf == outbuf)
- goto done;
-
- if (outbuf->freeze_start || inbuf->freeze_start) {
- result = -1;
- goto done;
- }
-
- if (PRESERVE_PINNED(inbuf, &pinned, &last) < 0) {
- result = -1;
- goto done;
- }
-
- if (out_total_len == 0) {
- /* There might be an empty chain at the start of outbuf; free
- * it. */
- evbuffer_free_all_chains(outbuf->first);
- COPY_CHAIN(outbuf, inbuf);
- } else {
- PREPEND_CHAIN(outbuf, inbuf);
- }
-
- RESTORE_PINNED(inbuf, pinned, last);
-
- inbuf->n_del_for_cb += in_total_len;
- outbuf->n_add_for_cb += in_total_len;
-
- evbuffer_invoke_callbacks_(inbuf);
- evbuffer_invoke_callbacks_(outbuf);
-done:
- EVBUFFER_UNLOCK2(inbuf, outbuf);
- return result;
-}
-
-int
-evbuffer_drain(struct evbuffer *buf, size_t len)
-{
- struct evbuffer_chain *chain, *next;
- size_t remaining, old_len;
- int result = 0;
-
- EVBUFFER_LOCK(buf);
- old_len = buf->total_len;
-
- if (old_len == 0)
- goto done;
-
- if (buf->freeze_start) {
- result = -1;
- goto done;
- }
-
- if (len >= old_len && !HAS_PINNED_R(buf)) {
- len = old_len;
- for (chain = buf->first; chain != NULL; chain = next) {
- next = chain->next;
- evbuffer_chain_free(chain);
- }
-
- ZERO_CHAIN(buf);
- } else {
- if (len >= old_len)
- len = old_len;
-
- buf->total_len -= len;
- remaining = len;
- for (chain = buf->first;
- remaining >= chain->off;
- chain = next) {
- next = chain->next;
- remaining -= chain->off;
-
- if (chain == *buf->last_with_datap) {
- buf->last_with_datap = &buf->first;
- }
- if (&chain->next == buf->last_with_datap)
- buf->last_with_datap = &buf->first;
-
- if (CHAIN_PINNED_R(chain)) {
- EVUTIL_ASSERT(remaining == 0);
- chain->misalign += chain->off;
- chain->off = 0;
- break;
- } else
- evbuffer_chain_free(chain);
- }
-
- buf->first = chain;
- EVUTIL_ASSERT(chain && remaining <= chain->off);
- chain->misalign += remaining;
- chain->off -= remaining;
- }
-
- buf->n_del_for_cb += len;
- /* Tell someone about changes in this buffer */
- evbuffer_invoke_callbacks_(buf);
-
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-/* Reads data from an event buffer and drains the bytes read */
-int
-evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
-{
- ev_ssize_t n;
- EVBUFFER_LOCK(buf);
- n = evbuffer_copyout_from(buf, NULL, data_out, datlen);
- if (n > 0) {
- if (evbuffer_drain(buf, n)<0)
- n = -1;
- }
- EVBUFFER_UNLOCK(buf);
- return (int)n;
-}
-
-ev_ssize_t
-evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
-{
- return evbuffer_copyout_from(buf, NULL, data_out, datlen);
-}
-
-ev_ssize_t
-evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
- void *data_out, size_t datlen)
-{
- /*XXX fails badly on sendfile case. */
- struct evbuffer_chain *chain;
- char *data = data_out;
- size_t nread;
- ev_ssize_t result = 0;
- size_t pos_in_chain;
-
- EVBUFFER_LOCK(buf);
-
- if (pos) {
- if (datlen > (size_t)(EV_SSIZE_MAX - pos->pos)) {
- result = -1;
- goto done;
- }
- chain = pos->internal_.chain;
- pos_in_chain = pos->internal_.pos_in_chain;
- if (datlen + pos->pos > buf->total_len)
- datlen = buf->total_len - pos->pos;
- } else {
- chain = buf->first;
- pos_in_chain = 0;
- if (datlen > buf->total_len)
- datlen = buf->total_len;
- }
-
-
- if (datlen == 0)
- goto done;
-
- if (buf->freeze_start) {
- result = -1;
- goto done;
- }
-
- nread = datlen;
-
- while (datlen && datlen >= chain->off - pos_in_chain) {
- size_t copylen = chain->off - pos_in_chain;
- memcpy(data,
- chain->buffer + chain->misalign + pos_in_chain,
- copylen);
- data += copylen;
- datlen -= copylen;
-
- chain = chain->next;
- pos_in_chain = 0;
- EVUTIL_ASSERT(chain || datlen==0);
- }
-
- if (datlen) {
- EVUTIL_ASSERT(chain);
- EVUTIL_ASSERT(datlen+pos_in_chain <= chain->off);
-
- memcpy(data, chain->buffer + chain->misalign + pos_in_chain,
- datlen);
- }
-
- result = nread;
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-/* reads data from the src buffer to the dst buffer, avoids memcpy as
- * possible. */
-/* XXXX should return ev_ssize_t */
-int
-evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
- size_t datlen)
-{
- /*XXX We should have an option to force this to be zero-copy.*/
-
- /*XXX can fail badly on sendfile case. */
- struct evbuffer_chain *chain, *previous;
- size_t nread = 0;
- int result;
-
- EVBUFFER_LOCK2(src, dst);
-
- chain = previous = src->first;
-
- if (datlen == 0 || dst == src) {
- result = 0;
- goto done;
- }
-
- if (dst->freeze_end || src->freeze_start) {
- result = -1;
- goto done;
- }
-
- /* short-cut if there is no more data buffered */
- if (datlen >= src->total_len) {
- datlen = src->total_len;
- evbuffer_add_buffer(dst, src);
- result = (int)datlen; /*XXXX should return ev_ssize_t*/
- goto done;
- }
-
- /* removes chains if possible */
- while (chain->off <= datlen) {
- /* We can't remove the last with data from src unless we
- * remove all chains, in which case we would have done the if
- * block above */
- EVUTIL_ASSERT(chain != *src->last_with_datap);
- nread += chain->off;
- datlen -= chain->off;
- previous = chain;
- if (src->last_with_datap == &chain->next)
- src->last_with_datap = &src->first;
- chain = chain->next;
- }
-
- if (nread) {
- /* we can remove the chain */
- struct evbuffer_chain **chp;
- chp = evbuffer_free_trailing_empty_chains(dst);
-
- if (dst->first == NULL) {
- dst->first = src->first;
- } else {
- *chp = src->first;
- }
- dst->last = previous;
- previous->next = NULL;
- src->first = chain;
- advance_last_with_data(dst);
-
- dst->total_len += nread;
- dst->n_add_for_cb += nread;
- }
-
- /* we know that there is more data in the src buffer than
- * we want to read, so we manually drain the chain */
- evbuffer_add(dst, chain->buffer + chain->misalign, datlen);
- chain->misalign += datlen;
- chain->off -= datlen;
- nread += datlen;
-
- /* You might think we would want to increment dst->n_add_for_cb
- * here too. But evbuffer_add above already took care of that.
- */
- src->total_len -= nread;
- src->n_del_for_cb += nread;
-
- if (nread) {
- evbuffer_invoke_callbacks_(dst);
- evbuffer_invoke_callbacks_(src);
- }
- result = (int)nread;/*XXXX should change return type */
-
-done:
- EVBUFFER_UNLOCK2(src, dst);
- return result;
-}
-
-unsigned char *
-evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size)
-{
- struct evbuffer_chain *chain, *next, *tmp, *last_with_data;
- unsigned char *buffer, *result = NULL;
- ev_ssize_t remaining;
- int removed_last_with_data = 0;
- int removed_last_with_datap = 0;
-
- EVBUFFER_LOCK(buf);
-
- chain = buf->first;
-
- if (size < 0)
- size = buf->total_len;
- /* if size > buf->total_len, we cannot guarantee to the user that she
- * is going to have a long enough buffer afterwards; so we return
- * NULL */
- if (size == 0 || (size_t)size > buf->total_len)
- goto done;
-
- /* No need to pull up anything; the first size bytes are
- * already here. */
- if (chain->off >= (size_t)size) {
- result = chain->buffer + chain->misalign;
- goto done;
- }
-
- /* Make sure that none of the chains we need to copy from is pinned. */
- remaining = size - chain->off;
- EVUTIL_ASSERT(remaining >= 0);
- for (tmp=chain->next; tmp; tmp=tmp->next) {
- if (CHAIN_PINNED(tmp))
- goto done;
- if (tmp->off >= (size_t)remaining)
- break;
- remaining -= tmp->off;
- }
-
- if (CHAIN_PINNED(chain)) {
- size_t old_off = chain->off;
- if (CHAIN_SPACE_LEN(chain) < size - chain->off) {
- /* not enough room at end of chunk. */
- goto done;
- }
- buffer = CHAIN_SPACE_PTR(chain);
- tmp = chain;
- tmp->off = size;
- size -= old_off;
- chain = chain->next;
- } else if (chain->buffer_len - chain->misalign >= (size_t)size) {
- /* already have enough space in the first chain */
- size_t old_off = chain->off;
- buffer = chain->buffer + chain->misalign + chain->off;
- tmp = chain;
- tmp->off = size;
- size -= old_off;
- chain = chain->next;
- } else {
- if ((tmp = evbuffer_chain_new(size)) == NULL) {
- event_warn("%s: out of memory", __func__);
- goto done;
- }
- buffer = tmp->buffer;
- tmp->off = size;
- buf->first = tmp;
- }
-
- /* TODO(niels): deal with buffers that point to NULL like sendfile */
-
- /* Copy and free every chunk that will be entirely pulled into tmp */
- last_with_data = *buf->last_with_datap;
- for (; chain != NULL && (size_t)size >= chain->off; chain = next) {
- next = chain->next;
-
- memcpy(buffer, chain->buffer + chain->misalign, chain->off);
- size -= chain->off;
- buffer += chain->off;
- if (chain == last_with_data)
- removed_last_with_data = 1;
- if (&chain->next == buf->last_with_datap)
- removed_last_with_datap = 1;
-
- evbuffer_chain_free(chain);
- }
-
- if (chain != NULL) {
- memcpy(buffer, chain->buffer + chain->misalign, size);
- chain->misalign += size;
- chain->off -= size;
- } else {
- buf->last = tmp;
- }
-
- tmp->next = chain;
-
- if (removed_last_with_data) {
- buf->last_with_datap = &buf->first;
- } else if (removed_last_with_datap) {
- if (buf->first->next && buf->first->next->off)
- buf->last_with_datap = &buf->first->next;
- else
- buf->last_with_datap = &buf->first;
- }
-
- result = (tmp->buffer + tmp->misalign);
-
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-/*
- * 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)
-{
- return evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY);
-}
-
-static inline ev_ssize_t
-evbuffer_strchr(struct evbuffer_ptr *it, const char chr)
-{
- struct evbuffer_chain *chain = it->internal_.chain;
- size_t i = it->internal_.pos_in_chain;
- while (chain != NULL) {
- char *buffer = (char *)chain->buffer + chain->misalign;
- char *cp = memchr(buffer+i, chr, chain->off-i);
- if (cp) {
- it->internal_.chain = chain;
- it->internal_.pos_in_chain = cp - buffer;
- it->pos += (cp - buffer - i);
- return it->pos;
- }
- it->pos += chain->off - i;
- i = 0;
- chain = chain->next;
- }
-
- return (-1);
-}
-
-static inline char *
-find_eol_char(char *s, size_t len)
-{
-#define CHUNK_SZ 128
- /* Lots of benchmarking found this approach to be faster in practice
- * than doing two memchrs over the whole buffer, doin a memchr on each
- * char of the buffer, or trying to emulate memchr by hand. */
- char *s_end, *cr, *lf;
- s_end = s+len;
- while (s < s_end) {
- size_t chunk = (s + CHUNK_SZ < s_end) ? CHUNK_SZ : (s_end - s);
- cr = memchr(s, '\r', chunk);
- lf = memchr(s, '\n', chunk);
- if (cr) {
- if (lf && lf < cr)
- return lf;
- return cr;
- } else if (lf) {
- return lf;
- }
- s += CHUNK_SZ;
- }
-
- return NULL;
-#undef CHUNK_SZ
-}
-
-static ev_ssize_t
-evbuffer_find_eol_char(struct evbuffer_ptr *it)
-{
- struct evbuffer_chain *chain = it->internal_.chain;
- size_t i = it->internal_.pos_in_chain;
- while (chain != NULL) {
- char *buffer = (char *)chain->buffer + chain->misalign;
- char *cp = find_eol_char(buffer+i, chain->off-i);
- if (cp) {
- it->internal_.chain = chain;
- it->internal_.pos_in_chain = cp - buffer;
- it->pos += (cp - buffer) - i;
- return it->pos;
- }
- it->pos += chain->off - i;
- i = 0;
- chain = chain->next;
- }
-
- return (-1);
-}
-
-static inline int
-evbuffer_strspn(
- struct evbuffer_ptr *ptr, const char *chrset)
-{
- int count = 0;
- struct evbuffer_chain *chain = ptr->internal_.chain;
- size_t i = ptr->internal_.pos_in_chain;
-
- if (!chain)
- return 0;
-
- while (1) {
- char *buffer = (char *)chain->buffer + chain->misalign;
- for (; i < chain->off; ++i) {
- const char *p = chrset;
- while (*p) {
- if (buffer[i] == *p++)
- goto next;
- }
- ptr->internal_.chain = chain;
- ptr->internal_.pos_in_chain = i;
- ptr->pos += count;
- return count;
- next:
- ++count;
- }
- i = 0;
-
- if (! chain->next) {
- ptr->internal_.chain = chain;
- ptr->internal_.pos_in_chain = i;
- ptr->pos += count;
- return count;
- }
-
- chain = chain->next;
- }
-}
-
-
-static inline int
-evbuffer_getchr(struct evbuffer_ptr *it)
-{
- struct evbuffer_chain *chain = it->internal_.chain;
- size_t off = it->internal_.pos_in_chain;
-
- if (chain == NULL)
- return -1;
-
- return (unsigned char)chain->buffer[chain->misalign + off];
-}
-
-struct evbuffer_ptr
-evbuffer_search_eol(struct evbuffer *buffer,
- struct evbuffer_ptr *start, size_t *eol_len_out,
- enum evbuffer_eol_style eol_style)
-{
- struct evbuffer_ptr it, it2;
- size_t extra_drain = 0;
- int ok = 0;
-
- /* Avoid locking in trivial edge cases */
- if (start && start->internal_.chain == NULL) {
- PTR_NOT_FOUND(&it);
- if (eol_len_out)
- *eol_len_out = extra_drain;
- return it;
- }
-
- EVBUFFER_LOCK(buffer);
-
- if (start) {
- memcpy(&it, start, sizeof(it));
- } else {
- it.pos = 0;
- it.internal_.chain = buffer->first;
- it.internal_.pos_in_chain = 0;
- }
-
- /* the eol_style determines our first stop character and how many
- * characters we are going to drain afterwards. */
- switch (eol_style) {
- case EVBUFFER_EOL_ANY:
- if (evbuffer_find_eol_char(&it) < 0)
- goto done;
- memcpy(&it2, &it, sizeof(it));
- extra_drain = evbuffer_strspn(&it2, "\r\n");
- break;
- case EVBUFFER_EOL_CRLF_STRICT: {
- it = evbuffer_search(buffer, "\r\n", 2, &it);
- if (it.pos < 0)
- goto done;
- extra_drain = 2;
- break;
- }
- case EVBUFFER_EOL_CRLF: {
- ev_ssize_t start_pos = it.pos;
- /* Look for a LF ... */
- if (evbuffer_strchr(&it, '\n') < 0)
- goto done;
- extra_drain = 1;
- /* ... optionally preceeded by a CR. */
- if (it.pos == start_pos)
- break; /* If the first character is \n, don't back up */
- /* This potentially does an extra linear walk over the first
- * few chains. Probably, that's not too expensive unless you
- * have a really pathological setup. */
- memcpy(&it2, &it, sizeof(it));
- if (evbuffer_ptr_subtract(buffer, &it2, 1)<0)
- break;
- if (evbuffer_getchr(&it2) == '\r') {
- memcpy(&it, &it2, sizeof(it));
- extra_drain = 2;
- }
- break;
- }
- case EVBUFFER_EOL_LF:
- if (evbuffer_strchr(&it, '\n') < 0)
- goto done;
- extra_drain = 1;
- break;
- case EVBUFFER_EOL_NUL:
- if (evbuffer_strchr(&it, '\0') < 0)
- goto done;
- extra_drain = 1;
- break;
- default:
- goto done;
- }
-
- ok = 1;
-done:
- EVBUFFER_UNLOCK(buffer);
-
- if (!ok)
- PTR_NOT_FOUND(&it);
- if (eol_len_out)
- *eol_len_out = extra_drain;
-
- return it;
-}
-
-char *
-evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
- enum evbuffer_eol_style eol_style)
-{
- struct evbuffer_ptr it;
- char *line;
- size_t n_to_copy=0, extra_drain=0;
- char *result = NULL;
-
- EVBUFFER_LOCK(buffer);
-
- if (buffer->freeze_start) {
- goto done;
- }
-
- it = evbuffer_search_eol(buffer, NULL, &extra_drain, eol_style);
- if (it.pos < 0)
- goto done;
- n_to_copy = it.pos;
-
- if ((line = mm_malloc(n_to_copy+1)) == NULL) {
- event_warn("%s: out of memory", __func__);
- goto done;
- }
-
- evbuffer_remove(buffer, line, n_to_copy);
- line[n_to_copy] = '\0';
-
- evbuffer_drain(buffer, extra_drain);
- result = line;
-done:
- EVBUFFER_UNLOCK(buffer);
-
- if (n_read_out)
- *n_read_out = result ? n_to_copy : 0;
-
- return result;
-}
-
-#define EVBUFFER_CHAIN_MAX_AUTO_SIZE 4096
-
-/* Adds data to an event buffer */
-
-int
-evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
-{
- struct evbuffer_chain *chain, *tmp;
- const unsigned char *data = data_in;
- size_t remain, to_alloc;
- int result = -1;
-
- EVBUFFER_LOCK(buf);
-
- if (buf->freeze_end) {
- goto done;
- }
- /* Prevent buf->total_len overflow */
- if (datlen > EV_SIZE_MAX - buf->total_len) {
- goto done;
- }
-
- chain = buf->last;
-
- /* If there are no chains allocated for this buffer, allocate one
- * big enough to hold all the data. */
- if (chain == NULL) {
- chain = evbuffer_chain_new(datlen);
- if (!chain)
- goto done;
- evbuffer_chain_insert(buf, chain);
- }
-
- if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
- /* Always true for mutable buffers */
- EVUTIL_ASSERT(chain->misalign >= 0 &&
- (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
- remain = chain->buffer_len - (size_t)chain->misalign - chain->off;
- if (remain >= datlen) {
- /* there's enough space to hold all the data in the
- * current last chain */
- memcpy(chain->buffer + chain->misalign + chain->off,
- data, datlen);
- chain->off += datlen;
- buf->total_len += datlen;
- buf->n_add_for_cb += datlen;
- goto out;
- } else if (!CHAIN_PINNED(chain) &&
- evbuffer_chain_should_realign(chain, datlen)) {
- /* we can fit the data into the misalignment */
- evbuffer_chain_align(chain);
-
- memcpy(chain->buffer + chain->off, data, datlen);
- chain->off += datlen;
- buf->total_len += datlen;
- buf->n_add_for_cb += datlen;
- goto out;
- }
- } else {
- /* we cannot write any data to the last chain */
- remain = 0;
- }
-
- /* we need to add another chain */
- to_alloc = chain->buffer_len;
- if (to_alloc <= EVBUFFER_CHAIN_MAX_AUTO_SIZE/2)
- to_alloc <<= 1;
- if (datlen > to_alloc)
- to_alloc = datlen;
- tmp = evbuffer_chain_new(to_alloc);
- if (tmp == NULL)
- goto done;
-
- if (remain) {
- memcpy(chain->buffer + chain->misalign + chain->off,
- data, remain);
- chain->off += remain;
- buf->total_len += remain;
- buf->n_add_for_cb += remain;
- }
-
- data += remain;
- datlen -= remain;
-
- memcpy(tmp->buffer, data, datlen);
- tmp->off = datlen;
- evbuffer_chain_insert(buf, tmp);
- buf->n_add_for_cb += datlen;
-
-out:
- evbuffer_invoke_callbacks_(buf);
- result = 0;
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-int
-evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
-{
- struct evbuffer_chain *chain, *tmp;
- int result = -1;
-
- EVBUFFER_LOCK(buf);
-
- if (buf->freeze_start) {
- goto done;
- }
- if (datlen > EV_SIZE_MAX - buf->total_len) {
- goto done;
- }
-
- chain = buf->first;
-
- if (chain == NULL) {
- chain = evbuffer_chain_new(datlen);
- if (!chain)
- goto done;
- evbuffer_chain_insert(buf, chain);
- }
-
- /* we cannot touch immutable buffers */
- if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
- /* Always true for mutable buffers */
- EVUTIL_ASSERT(chain->misalign >= 0 &&
- (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);
-
- /* If this chain is empty, we can treat it as
- * 'empty at the beginning' rather than 'empty at the end' */
- if (chain->off == 0)
- chain->misalign = chain->buffer_len;
-
- if ((size_t)chain->misalign >= datlen) {
- /* we have enough space to fit everything */
- memcpy(chain->buffer + chain->misalign - datlen,
- data, datlen);
- chain->off += datlen;
- chain->misalign -= datlen;
- buf->total_len += datlen;
- buf->n_add_for_cb += datlen;
- goto out;
- } else if (chain->misalign) {
- /* we can only fit some of the data. */
- memcpy(chain->buffer,
- (char*)data + datlen - chain->misalign,
- (size_t)chain->misalign);
- chain->off += (size_t)chain->misalign;
- buf->total_len += (size_t)chain->misalign;
- buf->n_add_for_cb += (size_t)chain->misalign;
- datlen -= (size_t)chain->misalign;
- chain->misalign = 0;
- }
- }
-
- /* we need to add another chain */
- if ((tmp = evbuffer_chain_new(datlen)) == NULL)
- goto done;
- buf->first = tmp;
- if (buf->last_with_datap == &buf->first)
- buf->last_with_datap = &tmp->next;
-
- tmp->next = chain;
-
- tmp->off = datlen;
- EVUTIL_ASSERT(datlen <= tmp->buffer_len);
- tmp->misalign = tmp->buffer_len - datlen;
-
- memcpy(tmp->buffer + tmp->misalign, data, datlen);
- buf->total_len += datlen;
- buf->n_add_for_cb += (size_t)chain->misalign;
-
-out:
- evbuffer_invoke_callbacks_(buf);
- result = 0;
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-/** Helper: realigns the memory in chain->buffer so that misalign is 0. */
-static void
-evbuffer_chain_align(struct evbuffer_chain *chain)
-{
- EVUTIL_ASSERT(!(chain->flags & EVBUFFER_IMMUTABLE));
- EVUTIL_ASSERT(!(chain->flags & EVBUFFER_MEM_PINNED_ANY));
- memmove(chain->buffer, chain->buffer + chain->misalign, chain->off);
- chain->misalign = 0;
-}
-
-#define MAX_TO_COPY_IN_EXPAND 4096
-#define MAX_TO_REALIGN_IN_EXPAND 2048
-
-/** Helper: return true iff we should realign chain to fit datalen bytes of
- data in it. */
-static int
-evbuffer_chain_should_realign(struct evbuffer_chain *chain,
- size_t datlen)
-{
- return chain->buffer_len - chain->off >= datlen &&
- (chain->off < chain->buffer_len / 2) &&
- (chain->off <= MAX_TO_REALIGN_IN_EXPAND);
-}
-
-/* Expands the available space in the event buffer to at least datlen, all in
- * a single chunk. Return that chunk. */
-static struct evbuffer_chain *
-evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
-{
- struct evbuffer_chain *chain, **chainp;
- struct evbuffer_chain *result = NULL;
- ASSERT_EVBUFFER_LOCKED(buf);
-
- chainp = buf->last_with_datap;
-
- /* XXX If *chainp is no longer writeable, but has enough space in its
- * misalign, this might be a bad idea: we could still use *chainp, not
- * (*chainp)->next. */
- if (*chainp && CHAIN_SPACE_LEN(*chainp) == 0)
- chainp = &(*chainp)->next;
-
- /* 'chain' now points to the first chain with writable space (if any)
- * We will either use it, realign it, replace it, or resize it. */
- chain = *chainp;
-
- if (chain == NULL ||
- (chain->flags & (EVBUFFER_IMMUTABLE|EVBUFFER_MEM_PINNED_ANY))) {
- /* We can't use the last_with_data chain at all. Just add a
- * new one that's big enough. */
- goto insert_new;
- }
-
- /* If we can fit all the data, then we don't have to do anything */
- if (CHAIN_SPACE_LEN(chain) >= datlen) {
- result = chain;
- goto ok;
- }
-
- /* If the chain is completely empty, just replace it by adding a new
- * empty chain. */
- if (chain->off == 0) {
- goto insert_new;
- }
-
- /* If the misalignment plus the remaining space fulfills our data
- * needs, we could just force an alignment to happen. Afterwards, we
- * have enough space. But only do this if we're saving a lot of space
- * and not moving too much data. Otherwise the space savings are
- * probably offset by the time lost in copying.
- */
- if (evbuffer_chain_should_realign(chain, datlen)) {
- evbuffer_chain_align(chain);
- result = chain;
- goto ok;
- }
-
- /* At this point, we can either resize the last chunk with space in
- * it, use the next chunk after it, or If we add a new chunk, we waste
- * CHAIN_SPACE_LEN(chain) bytes in the former last chunk. If we
- * resize, we have to copy chain->off bytes.
- */
-
- /* Would expanding this chunk be affordable and worthwhile? */
- if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
- chain->off > MAX_TO_COPY_IN_EXPAND ||
- (datlen < EVBUFFER_CHAIN_MAX &&
- EVBUFFER_CHAIN_MAX - datlen >= chain->off)) {
- /* It's not worth resizing this chain. Can the next one be
- * used? */
- if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
- /* Yes, we can just use the next chain (which should
- * be empty. */
- result = chain->next;
- goto ok;
- } else {
- /* No; append a new chain (which will free all
- * terminal empty chains.) */
- goto insert_new;
- }
- } else {
- /* Okay, we're going to try to resize this chain: Not doing so
- * would waste at least 1/8 of its current allocation, and we
- * can do so without having to copy more than
- * MAX_TO_COPY_IN_EXPAND bytes. */
- /* figure out how much space we need */
- size_t length = chain->off + datlen;
- struct evbuffer_chain *tmp = evbuffer_chain_new(length);
- if (tmp == NULL)
- goto err;
-
- /* copy the data over that we had so far */
- tmp->off = chain->off;
- memcpy(tmp->buffer, chain->buffer + chain->misalign,
- chain->off);
- /* fix up the list */
- EVUTIL_ASSERT(*chainp == chain);
- result = *chainp = tmp;
-
- if (buf->last == chain)
- buf->last = tmp;
-
- tmp->next = chain->next;
- evbuffer_chain_free(chain);
- goto ok;
- }
-
-insert_new:
- result = evbuffer_chain_insert_new(buf, datlen);
- if (!result)
- goto err;
-ok:
- EVUTIL_ASSERT(result);
- EVUTIL_ASSERT(CHAIN_SPACE_LEN(result) >= datlen);
-err:
- return result;
-}
-
-/* Make sure that datlen bytes are available for writing in the last n
- * chains. Never copies or moves data. */
-int
-evbuffer_expand_fast_(struct evbuffer *buf, size_t datlen, int n)
-{
- struct evbuffer_chain *chain = buf->last, *tmp, *next;
- size_t avail;
- int used;
-
- ASSERT_EVBUFFER_LOCKED(buf);
- EVUTIL_ASSERT(n >= 2);
-
- if (chain == NULL || (chain->flags & EVBUFFER_IMMUTABLE)) {
- /* There is no last chunk, or we can't touch the last chunk.
- * Just add a new chunk. */
- chain = evbuffer_chain_new(datlen);
- if (chain == NULL)
- return (-1);
-
- evbuffer_chain_insert(buf, chain);
- return (0);
- }
-
- used = 0; /* number of chains we're using space in. */
- avail = 0; /* how much space they have. */
- /* How many bytes can we stick at the end of buffer as it is? Iterate
- * over the chains at the end of the buffer, tring to see how much
- * space we have in the first n. */
- for (chain = *buf->last_with_datap; chain; chain = chain->next) {
- if (chain->off) {
- size_t space = (size_t) CHAIN_SPACE_LEN(chain);
- EVUTIL_ASSERT(chain == *buf->last_with_datap);
- if (space) {
- avail += space;
- ++used;
- }
- } else {
- /* No data in chain; realign it. */
- chain->misalign = 0;
- avail += chain->buffer_len;
- ++used;
- }
- if (avail >= datlen) {
- /* There is already enough space. Just return */
- return (0);
- }
- if (used == n)
- break;
- }
-
- /* There wasn't enough space in the first n chains with space in
- * them. Either add a new chain with enough space, or replace all
- * empty chains with one that has enough space, depending on n. */
- if (used < n) {
- /* The loop ran off the end of the chains before it hit n
- * chains; we can add another. */
- EVUTIL_ASSERT(chain == NULL);
-
- tmp = evbuffer_chain_new(datlen - avail);
- if (tmp == NULL)
- return (-1);
-
- buf->last->next = tmp;
- buf->last = tmp;
- /* (we would only set last_with_data if we added the first
- * chain. But if the buffer had no chains, we would have
- * just allocated a new chain earlier) */
- return (0);
- } else {
- /* Nuke _all_ the empty chains. */
- int rmv_all = 0; /* True iff we removed last_with_data. */
- chain = *buf->last_with_datap;
- if (!chain->off) {
- EVUTIL_ASSERT(chain == buf->first);
- rmv_all = 1;
- avail = 0;
- } else {
- /* can't overflow, since only mutable chains have
- * huge misaligns. */
- avail = (size_t) CHAIN_SPACE_LEN(chain);
- chain = chain->next;
- }
-
-
- for (; chain; chain = next) {
- next = chain->next;
- EVUTIL_ASSERT(chain->off == 0);
- evbuffer_chain_free(chain);
- }
- EVUTIL_ASSERT(datlen >= avail);
- tmp = evbuffer_chain_new(datlen - avail);
- if (tmp == NULL) {
- if (rmv_all) {
- ZERO_CHAIN(buf);
- } else {
- buf->last = *buf->last_with_datap;
- (*buf->last_with_datap)->next = NULL;
- }
- return (-1);
- }
-
- if (rmv_all) {
- buf->first = buf->last = tmp;
- buf->last_with_datap = &buf->first;
- } else {
- (*buf->last_with_datap)->next = tmp;
- buf->last = tmp;
- }
- return (0);
- }
-}
-
-int
-evbuffer_expand(struct evbuffer *buf, size_t datlen)
-{
- struct evbuffer_chain *chain;
-
- EVBUFFER_LOCK(buf);
- chain = evbuffer_expand_singlechain(buf, datlen);
- EVBUFFER_UNLOCK(buf);
- return chain ? 0 : -1;
-}
-
-/*
- * Reads data from a file descriptor into a buffer.
- */
-
-#if defined(EVENT__HAVE_SYS_UIO_H) || defined(_WIN32)
-#define USE_IOVEC_IMPL
-#endif
-
-#ifdef USE_IOVEC_IMPL
-
-#ifdef EVENT__HAVE_SYS_UIO_H
-/* number of iovec we use for writev, fragmentation is going to determine
- * how much we end up writing */
-
-#define DEFAULT_WRITE_IOVEC 128
-
-#if defined(UIO_MAXIOV) && UIO_MAXIOV < DEFAULT_WRITE_IOVEC
-#define NUM_WRITE_IOVEC UIO_MAXIOV
-#elif defined(IOV_MAX) && IOV_MAX < DEFAULT_WRITE_IOVEC
-#define NUM_WRITE_IOVEC IOV_MAX
-#else
-#define NUM_WRITE_IOVEC DEFAULT_WRITE_IOVEC
-#endif
-
-#define IOV_TYPE struct iovec
-#define IOV_PTR_FIELD iov_base
-#define IOV_LEN_FIELD iov_len
-#define IOV_LEN_TYPE size_t
-#else
-#define NUM_WRITE_IOVEC 16
-#define IOV_TYPE WSABUF
-#define IOV_PTR_FIELD buf
-#define IOV_LEN_FIELD len
-#define IOV_LEN_TYPE unsigned long
-#endif
-#endif
-#define NUM_READ_IOVEC 4
-
-#define EVBUFFER_MAX_READ 4096
-
-/** Helper function to figure out which space to use for reading data into
- an evbuffer. Internal use only.
-
- @param buf The buffer to read into
- @param howmuch How much we want to read.
- @param vecs An array of two or more iovecs or WSABUFs.
- @param n_vecs_avail The length of vecs
- @param chainp A pointer to a variable to hold the first chain we're
- reading into.
- @param exact Boolean: if true, we do not provide more than 'howmuch'
- space in the vectors, even if more space is available.
- @return The number of buffers we're using.
- */
-int
-evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
- struct evbuffer_iovec *vecs, int n_vecs_avail,
- struct evbuffer_chain ***chainp, int exact)
-{
- struct evbuffer_chain *chain;
- struct evbuffer_chain **firstchainp;
- size_t so_far;
- int i;
- ASSERT_EVBUFFER_LOCKED(buf);
-
- if (howmuch < 0)
- return -1;
-
- so_far = 0;
- /* Let firstchain be the first chain with any space on it */
- firstchainp = buf->last_with_datap;
- if (CHAIN_SPACE_LEN(*firstchainp) == 0) {
- firstchainp = &(*firstchainp)->next;
- }
-
- chain = *firstchainp;
- for (i = 0; i < n_vecs_avail && so_far < (size_t)howmuch; ++i) {
- size_t avail = (size_t) CHAIN_SPACE_LEN(chain);
- if (avail > (howmuch - so_far) && exact)
- avail = howmuch - so_far;
- vecs[i].iov_base = CHAIN_SPACE_PTR(chain);
- vecs[i].iov_len = avail;
- so_far += avail;
- chain = chain->next;
- }
-
- *chainp = firstchainp;
- return i;
-}
-
-static int
-get_n_bytes_readable_on_socket(evutil_socket_t fd)
-{
-#if defined(FIONREAD) && defined(_WIN32)
- unsigned long lng = EVBUFFER_MAX_READ;
- if (ioctlsocket(fd, FIONREAD, &lng) < 0)
- return -1;
- /* Can overflow, but mostly harmlessly. XXXX */
- return (int)lng;
-#elif defined(FIONREAD)
- int n = EVBUFFER_MAX_READ;
- if (ioctl(fd, FIONREAD, &n) < 0)
- return -1;
- return n;
-#else
- return EVBUFFER_MAX_READ;
-#endif
-}
-
-/* TODO(niels): should this function return ev_ssize_t and take ev_ssize_t
- * as howmuch? */
-int
-evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
-{
- struct evbuffer_chain **chainp;
- int n;
- int result;
-
-#ifdef USE_IOVEC_IMPL
- int nvecs, i, remaining;
-#else
- struct evbuffer_chain *chain;
- unsigned char *p;
-#endif
-
- EVBUFFER_LOCK(buf);
-
- if (buf->freeze_end) {
- result = -1;
- goto done;
- }
-
- n = get_n_bytes_readable_on_socket(fd);
- if (n <= 0 || n > EVBUFFER_MAX_READ)
- n = EVBUFFER_MAX_READ;
- if (howmuch < 0 || howmuch > n)
- howmuch = n;
-
-#ifdef USE_IOVEC_IMPL
- /* Since we can use iovecs, we're willing to use the last
- * NUM_READ_IOVEC chains. */
- if (evbuffer_expand_fast_(buf, howmuch, NUM_READ_IOVEC) == -1) {
- result = -1;
- goto done;
- } else {
- IOV_TYPE vecs[NUM_READ_IOVEC];
-#ifdef EVBUFFER_IOVEC_IS_NATIVE_
- nvecs = evbuffer_read_setup_vecs_(buf, howmuch, vecs,
- NUM_READ_IOVEC, &chainp, 1);
-#else
- /* We aren't using the native struct iovec. Therefore,
- we are on win32. */
- struct evbuffer_iovec ev_vecs[NUM_READ_IOVEC];
- nvecs = evbuffer_read_setup_vecs_(buf, howmuch, ev_vecs, 2,
- &chainp, 1);
-
- for (i=0; i < nvecs; ++i)
- WSABUF_FROM_EVBUFFER_IOV(&vecs[i], &ev_vecs[i]);
-#endif
-
-#ifdef _WIN32
- {
- DWORD bytesRead;
- DWORD flags=0;
- if (WSARecv(fd, vecs, nvecs, &bytesRead, &flags, NULL, NULL)) {
- /* The read failed. It might be a close,
- * or it might be an error. */
- if (WSAGetLastError() == WSAECONNABORTED)
- n = 0;
- else
- n = -1;
- } else
- n = bytesRead;
- }
-#else
- n = readv(fd, vecs, nvecs);
-#endif
- }
-
-#else /*!USE_IOVEC_IMPL*/
- /* If we don't have FIONREAD, we might waste some space here */
- /* XXX we _will_ waste some space here if there is any space left
- * over on buf->last. */
- if ((chain = evbuffer_expand_singlechain(buf, howmuch)) == NULL) {
- result = -1;
- goto done;
- }
-
- /* We can append new data at this point */
- p = chain->buffer + chain->misalign + chain->off;
-
-#ifndef _WIN32
- n = read(fd, p, howmuch);
-#else
- n = recv(fd, p, howmuch, 0);
-#endif
-#endif /* USE_IOVEC_IMPL */
-
- if (n == -1) {
- result = -1;
- goto done;
- }
- if (n == 0) {
- result = 0;
- goto done;
- }
-
-#ifdef USE_IOVEC_IMPL
- remaining = n;
- for (i=0; i < nvecs; ++i) {
- /* can't overflow, since only mutable chains have
- * huge misaligns. */
- size_t space = (size_t) CHAIN_SPACE_LEN(*chainp);
- /* XXXX This is a kludge that can waste space in perverse
- * situations. */
- if (space > EVBUFFER_CHAIN_MAX)
- space = EVBUFFER_CHAIN_MAX;
- if ((ev_ssize_t)space < remaining) {
- (*chainp)->off += space;
- remaining -= (int)space;
- } else {
- (*chainp)->off += remaining;
- buf->last_with_datap = chainp;
- break;
- }
- chainp = &(*chainp)->next;
- }
-#else
- chain->off += n;
- advance_last_with_data(buf);
-#endif
- buf->total_len += n;
- buf->n_add_for_cb += n;
-
- /* Tell someone about changes in this buffer */
- evbuffer_invoke_callbacks_(buf);
- result = n;
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-#ifdef USE_IOVEC_IMPL
-static inline int
-evbuffer_write_iovec(struct evbuffer *buffer, evutil_socket_t fd,
- ev_ssize_t howmuch)
-{
- IOV_TYPE iov[NUM_WRITE_IOVEC];
- struct evbuffer_chain *chain = buffer->first;
- int n, i = 0;
-
- if (howmuch < 0)
- return -1;
-
- ASSERT_EVBUFFER_LOCKED(buffer);
- /* XXX make this top out at some maximal data length? if the
- * buffer has (say) 1MB in it, split over 128 chains, there's
- * no way it all gets written in one go. */
- while (chain != NULL && i < NUM_WRITE_IOVEC && howmuch) {
-#ifdef USE_SENDFILE
- /* we cannot write the file info via writev */
- if (chain->flags & EVBUFFER_SENDFILE)
- break;
-#endif
- iov[i].IOV_PTR_FIELD = (void *) (chain->buffer + chain->misalign);
- if ((size_t)howmuch >= chain->off) {
- /* XXXcould be problematic when windows supports mmap*/
- iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)chain->off;
- howmuch -= chain->off;
- } else {
- /* XXXcould be problematic when windows supports mmap*/
- iov[i++].IOV_LEN_FIELD = (IOV_LEN_TYPE)howmuch;
- break;
- }
- chain = chain->next;
- }
- if (! i)
- return 0;
-
-#ifdef _WIN32
- {
- DWORD bytesSent;
- if (WSASend(fd, iov, i, &bytesSent, 0, NULL, NULL))
- n = -1;
- else
- n = bytesSent;
- }
-#else
- n = writev(fd, iov, i);
-#endif
- return (n);
-}
-#endif
-
-#ifdef USE_SENDFILE
-static inline int
-evbuffer_write_sendfile(struct evbuffer *buffer, evutil_socket_t dest_fd,
- ev_ssize_t howmuch)
-{
- struct evbuffer_chain *chain = buffer->first;
- struct evbuffer_chain_file_segment *info =
- EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment,
- chain);
- const int source_fd = info->segment->fd;
-#if defined(SENDFILE_IS_MACOSX) || defined(SENDFILE_IS_FREEBSD)
- int res;
- ev_off_t len = chain->off;
-#elif defined(SENDFILE_IS_LINUX) || defined(SENDFILE_IS_SOLARIS)
- ev_ssize_t res;
- ev_off_t offset = chain->misalign;
-#endif
-
- ASSERT_EVBUFFER_LOCKED(buffer);
-
-#if defined(SENDFILE_IS_MACOSX)
- res = sendfile(source_fd, dest_fd, chain->misalign, &len, NULL, 0);
- if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
- return (-1);
-
- return (len);
-#elif defined(SENDFILE_IS_FREEBSD)
- res = sendfile(source_fd, dest_fd, chain->misalign, chain->off, NULL, &len, 0);
- if (res == -1 && !EVUTIL_ERR_RW_RETRIABLE(errno))
- return (-1);
-
- return (len);
-#elif defined(SENDFILE_IS_LINUX)
- /* TODO(niels): implement splice */
- res = sendfile(dest_fd, source_fd, &offset, chain->off);
- if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
- /* if this is EAGAIN or EINTR return 0; otherwise, -1 */
- return (0);
- }
- return (res);
-#elif defined(SENDFILE_IS_SOLARIS)
- {
- const off_t offset_orig = offset;
- res = sendfile(dest_fd, source_fd, &offset, chain->off);
- if (res == -1 && EVUTIL_ERR_RW_RETRIABLE(errno)) {
- if (offset - offset_orig)
- return offset - offset_orig;
- /* if this is EAGAIN or EINTR and no bytes were
- * written, return 0 */
- return (0);
- }
- return (res);
- }
-#endif
-}
-#endif
-
-int
-evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
- ev_ssize_t howmuch)
-{
- int n = -1;
-
- EVBUFFER_LOCK(buffer);
-
- if (buffer->freeze_start) {
- goto done;
- }
-
- if (howmuch < 0 || (size_t)howmuch > buffer->total_len)
- howmuch = buffer->total_len;
-
- if (howmuch > 0) {
-#ifdef USE_SENDFILE
- struct evbuffer_chain *chain = buffer->first;
- if (chain != NULL && (chain->flags & EVBUFFER_SENDFILE))
- n = evbuffer_write_sendfile(buffer, fd, howmuch);
- else {
-#endif
-#ifdef USE_IOVEC_IMPL
- n = evbuffer_write_iovec(buffer, fd, howmuch);
-#elif defined(_WIN32)
- /* XXX(nickm) Don't disable this code until we know if
- * the WSARecv code above works. */
- void *p = evbuffer_pullup(buffer, howmuch);
- EVUTIL_ASSERT(p || !howmuch);
- n = send(fd, p, howmuch, 0);
-#else
- void *p = evbuffer_pullup(buffer, howmuch);
- EVUTIL_ASSERT(p || !howmuch);
- n = write(fd, p, howmuch);
-#endif
-#ifdef USE_SENDFILE
- }
-#endif
- }
-
- if (n > 0)
- evbuffer_drain(buffer, n);
-
-done:
- EVBUFFER_UNLOCK(buffer);
- return (n);
-}
-
-int
-evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd)
-{
- return evbuffer_write_atmost(buffer, fd, -1);
-}
-
-unsigned char *
-evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len)
-{
- unsigned char *search;
- struct evbuffer_ptr ptr;
-
- EVBUFFER_LOCK(buffer);
-
- ptr = evbuffer_search(buffer, (const char *)what, len, NULL);
- if (ptr.pos < 0) {
- search = NULL;
- } else {
- search = evbuffer_pullup(buffer, ptr.pos + len);
- if (search)
- search += ptr.pos;
- }
- EVBUFFER_UNLOCK(buffer);
- return search;
-}
-
-/* Subract <b>howfar</b> from the position of <b>pos</b> within
- * <b>buf</b>. Returns 0 on success, -1 on failure.
- *
- * This isn't exposed yet, because of potential inefficiency issues.
- * Maybe it should be. */
-static int
-evbuffer_ptr_subtract(struct evbuffer *buf, struct evbuffer_ptr *pos,
- size_t howfar)
-{
- if (pos->pos < 0)
- return -1;
- if (howfar > (size_t)pos->pos)
- return -1;
- if (pos->internal_.chain && howfar <= pos->internal_.pos_in_chain) {
- pos->internal_.pos_in_chain -= howfar;
- pos->pos -= howfar;
- return 0;
- } else {
- const size_t newpos = pos->pos - howfar;
- /* Here's the inefficient part: it walks over the
- * chains until we hit newpos. */
- return evbuffer_ptr_set(buf, pos, newpos, EVBUFFER_PTR_SET);
- }
-}
-
-int
-evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
- size_t position, enum evbuffer_ptr_how how)
-{
- size_t left = position;
- struct evbuffer_chain *chain = NULL;
- int result = 0;
-
- EVBUFFER_LOCK(buf);
-
- switch (how) {
- case EVBUFFER_PTR_SET:
- chain = buf->first;
- pos->pos = position;
- position = 0;
- break;
- case EVBUFFER_PTR_ADD:
- /* this avoids iterating over all previous chains if
- we just want to advance the position */
- if (pos->pos < 0 || EV_SIZE_MAX - position < (size_t)pos->pos) {
- EVBUFFER_UNLOCK(buf);
- return -1;
- }
- chain = pos->internal_.chain;
- pos->pos += position;
- position = pos->internal_.pos_in_chain;
- break;
- }
-
- EVUTIL_ASSERT(EV_SIZE_MAX - left >= position);
- while (chain && position + left >= chain->off) {
- left -= chain->off - position;
- chain = chain->next;
- position = 0;
- }
- if (chain) {
- pos->internal_.chain = chain;
- pos->internal_.pos_in_chain = position + left;
- } else if (left == 0) {
- /* The first byte in the (nonexistent) chain after the last chain */
- pos->internal_.chain = NULL;
- pos->internal_.pos_in_chain = 0;
- } else {
- PTR_NOT_FOUND(pos);
- result = -1;
- }
-
- EVBUFFER_UNLOCK(buf);
-
- return result;
-}
-
-/**
- Compare the bytes in buf at position pos to the len bytes in mem. Return
- less than 0, 0, or greater than 0 as memcmp.
- */
-static int
-evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
- const char *mem, size_t len)
-{
- struct evbuffer_chain *chain;
- size_t position;
- int r;
-
- ASSERT_EVBUFFER_LOCKED(buf);
-
- if (pos->pos < 0 ||
- EV_SIZE_MAX - len < (size_t)pos->pos ||
- pos->pos + len > buf->total_len)
- return -1;
-
- chain = pos->internal_.chain;
- position = pos->internal_.pos_in_chain;
- while (len && chain) {
- size_t n_comparable;
- if (len + position > chain->off)
- n_comparable = chain->off - position;
- else
- n_comparable = len;
- r = memcmp(chain->buffer + chain->misalign + position, mem,
- n_comparable);
- if (r)
- return r;
- mem += n_comparable;
- len -= n_comparable;
- position = 0;
- chain = chain->next;
- }
-
- return 0;
-}
-
-struct evbuffer_ptr
-evbuffer_search(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start)
-{
- return evbuffer_search_range(buffer, what, len, start, NULL);
-}
-
-struct evbuffer_ptr
-evbuffer_search_range(struct evbuffer *buffer, const char *what, size_t len, const struct evbuffer_ptr *start, const struct evbuffer_ptr *end)
-{
- struct evbuffer_ptr pos;
- struct evbuffer_chain *chain, *last_chain = NULL;
- const unsigned char *p;
- char first;
-
- EVBUFFER_LOCK(buffer);
-
- if (start) {
- memcpy(&pos, start, sizeof(pos));
- chain = pos.internal_.chain;
- } else {
- pos.pos = 0;
- chain = pos.internal_.chain = buffer->first;
- pos.internal_.pos_in_chain = 0;
- }
-
- if (end)
- last_chain = end->internal_.chain;
-
- if (!len || len > EV_SSIZE_MAX)
- goto done;
-
- first = what[0];
-
- while (chain) {
- const unsigned char *start_at =
- chain->buffer + chain->misalign +
- pos.internal_.pos_in_chain;
- p = memchr(start_at, first,
- chain->off - pos.internal_.pos_in_chain);
- if (p) {
- pos.pos += p - start_at;
- pos.internal_.pos_in_chain += p - start_at;
- if (!evbuffer_ptr_memcmp(buffer, &pos, what, len)) {
- if (end && pos.pos + (ev_ssize_t)len > end->pos)
- goto not_found;
- else
- goto done;
- }
- ++pos.pos;
- ++pos.internal_.pos_in_chain;
- if (pos.internal_.pos_in_chain == chain->off) {
- chain = pos.internal_.chain = chain->next;
- pos.internal_.pos_in_chain = 0;
- }
- } else {
- if (chain == last_chain)
- goto not_found;
- pos.pos += chain->off - pos.internal_.pos_in_chain;
- chain = pos.internal_.chain = chain->next;
- pos.internal_.pos_in_chain = 0;
- }
- }
-
-not_found:
- PTR_NOT_FOUND(&pos);
-done:
- EVBUFFER_UNLOCK(buffer);
- return pos;
-}
-
-int
-evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
- struct evbuffer_ptr *start_at,
- struct evbuffer_iovec *vec, int n_vec)
-{
- struct evbuffer_chain *chain;
- int idx = 0;
- ev_ssize_t len_so_far = 0;
-
- /* Avoid locking in trivial edge cases */
- if (start_at && start_at->internal_.chain == NULL)
- return 0;
-
- EVBUFFER_LOCK(buffer);
-
- if (start_at) {
- chain = start_at->internal_.chain;
- len_so_far = chain->off
- - start_at->internal_.pos_in_chain;
- idx = 1;
- if (n_vec > 0) {
- vec[0].iov_base = chain->buffer + chain->misalign
- + start_at->internal_.pos_in_chain;
- vec[0].iov_len = len_so_far;
- }
- chain = chain->next;
- } else {
- chain = buffer->first;
- }
-
- if (n_vec == 0 && len < 0) {
- /* If no vectors are provided and they asked for "everything",
- * pretend they asked for the actual available amount. */
- len = buffer->total_len;
- if (start_at) {
- len -= start_at->pos;
- }
- }
-
- while (chain) {
- if (len >= 0 && len_so_far >= len)
- break;
- if (idx<n_vec) {
- vec[idx].iov_base = chain->buffer + chain->misalign;
- vec[idx].iov_len = chain->off;
- } else if (len<0) {
- break;
- }
- ++idx;
- len_so_far += chain->off;
- chain = chain->next;
- }
-
- EVBUFFER_UNLOCK(buffer);
-
- return idx;
-}
-
-
-int
-evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
-{
- char *buffer;
- size_t space;
- int sz, result = -1;
- va_list aq;
- struct evbuffer_chain *chain;
-
-
- EVBUFFER_LOCK(buf);
-
- if (buf->freeze_end) {
- goto done;
- }
-
- /* make sure that at least some space is available */
- if ((chain = evbuffer_expand_singlechain(buf, 64)) == NULL)
- goto done;
-
- for (;;) {
-#if 0
- size_t used = chain->misalign + chain->off;
- buffer = (char *)chain->buffer + chain->misalign + chain->off;
- EVUTIL_ASSERT(chain->buffer_len >= used);
- space = chain->buffer_len - used;
-#endif
- buffer = (char*) CHAIN_SPACE_PTR(chain);
- space = (size_t) CHAIN_SPACE_LEN(chain);
-
-#ifndef va_copy
-#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
-#endif
- va_copy(aq, ap);
-
- sz = evutil_vsnprintf(buffer, space, fmt, aq);
-
- va_end(aq);
-
- if (sz < 0)
- goto done;
- if (INT_MAX >= EVBUFFER_CHAIN_MAX &&
- (size_t)sz >= EVBUFFER_CHAIN_MAX)
- goto done;
- if ((size_t)sz < space) {
- chain->off += sz;
- buf->total_len += sz;
- buf->n_add_for_cb += sz;
-
- advance_last_with_data(buf);
- evbuffer_invoke_callbacks_(buf);
- result = sz;
- goto done;
- }
- if ((chain = evbuffer_expand_singlechain(buf, sz + 1)) == NULL)
- goto done;
- }
- /* NOTREACHED */
-
-done:
- EVBUFFER_UNLOCK(buf);
- return result;
-}
-
-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);
-}
-
-int
-evbuffer_add_reference(struct evbuffer *outbuf,
- const void *data, size_t datlen,
- evbuffer_ref_cleanup_cb cleanupfn, void *extra)
-{
- struct evbuffer_chain *chain;
- struct evbuffer_chain_reference *info;
- int result = -1;
-
- chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_reference));
- if (!chain)
- return (-1);
- chain->flags |= EVBUFFER_REFERENCE | EVBUFFER_IMMUTABLE;
- chain->buffer = (unsigned char *)data;
- chain->buffer_len = datlen;
- chain->off = datlen;
-
- info = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_reference, chain);
- info->cleanupfn = cleanupfn;
- info->extra = extra;
-
- EVBUFFER_LOCK(outbuf);
- if (outbuf->freeze_end) {
- /* don't call chain_free; we do not want to actually invoke
- * the cleanup function */
- mm_free(chain);
- goto done;
- }
- evbuffer_chain_insert(outbuf, chain);
- outbuf->n_add_for_cb += datlen;
-
- evbuffer_invoke_callbacks_(outbuf);
-
- result = 0;
-done:
- EVBUFFER_UNLOCK(outbuf);
-
- return result;
-}
-
-/* TODO(niels): we may want to add to automagically convert to mmap, in
- * case evbuffer_remove() or evbuffer_pullup() are being used.
- */
-struct evbuffer_file_segment *
-evbuffer_file_segment_new(
- int fd, ev_off_t offset, ev_off_t length, unsigned flags)
-{
- struct evbuffer_file_segment *seg =
- mm_calloc(sizeof(struct evbuffer_file_segment), 1);
- if (!seg)
- return NULL;
- seg->refcnt = 1;
- seg->fd = fd;
- seg->flags = flags;
- seg->file_offset = offset;
- seg->cleanup_cb = NULL;
- seg->cleanup_cb_arg = NULL;
-#ifdef _WIN32
-#ifndef lseek
-#define lseek _lseeki64
-#endif
-#ifndef fstat
-#define fstat _fstat
-#endif
-#ifndef stat
-#define stat _stat
-#endif
-#endif
- if (length == -1) {
- struct stat st;
- if (fstat(fd, &st) < 0)
- goto err;
- length = st.st_size;
- }
- seg->length = length;
-
- if (offset < 0 || length < 0 ||
- ((ev_uint64_t)length > EVBUFFER_CHAIN_MAX) ||
- (ev_uint64_t)offset > (ev_uint64_t)(EVBUFFER_CHAIN_MAX - length))
- goto err;
-
-#if defined(USE_SENDFILE)
- if (!(flags & EVBUF_FS_DISABLE_SENDFILE)) {
- seg->can_sendfile = 1;
- goto done;
- }
-#endif
-
- if (evbuffer_file_segment_materialize(seg)<0)
- goto err;
-
-#if defined(USE_SENDFILE)
-done:
-#endif
- if (!(flags & EVBUF_FS_DISABLE_LOCKING)) {
- EVTHREAD_ALLOC_LOCK(seg->lock, 0);
- }
- return seg;
-err:
- mm_free(seg);
- return NULL;
-}
-
-#ifdef EVENT__HAVE_MMAP
-static long
-get_page_size(void)
-{
-#ifdef SC_PAGE_SIZE
- return sysconf(SC_PAGE_SIZE);
-#elif defined(_SC_PAGE_SIZE)
- return sysconf(_SC_PAGE_SIZE);
-#else
- return 1;
-#endif
-}
-#endif
-
-/* DOCDOC */
-/* Requires lock */
-static int
-evbuffer_file_segment_materialize(struct evbuffer_file_segment *seg)
-{
- const unsigned flags = seg->flags;
- const int fd = seg->fd;
- const ev_off_t length = seg->length;
- const ev_off_t offset = seg->file_offset;
-
- if (seg->contents)
- return 0; /* already materialized */
-
-#if defined(EVENT__HAVE_MMAP)
- if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
- off_t offset_rounded = 0, offset_leftover = 0;
- void *mapped;
- if (offset) {
- /* mmap implementations don't generally like us
- * to have an offset that isn't a round */
- long page_size = get_page_size();
- if (page_size == -1)
- goto err;
- offset_leftover = offset % page_size;
- offset_rounded = offset - offset_leftover;
- }
- mapped = mmap(NULL, length + offset_leftover,
- PROT_READ,
-#ifdef MAP_NOCACHE
- MAP_NOCACHE | /* ??? */
-#endif
-#ifdef MAP_FILE
- MAP_FILE |
-#endif
- MAP_PRIVATE,
- fd, offset_rounded);
- if (mapped == MAP_FAILED) {
- event_warn("%s: mmap(%d, %d, %zu) failed",
- __func__, fd, 0, (size_t)(offset + length));
- } else {
- seg->mapping = mapped;
- seg->contents = (char*)mapped+offset_leftover;
- seg->mmap_offset = 0;
- seg->is_mapping = 1;
- goto done;
- }
- }
-#endif
-#ifdef _WIN32
- if (!(flags & EVBUF_FS_DISABLE_MMAP)) {
- intptr_t h = _get_osfhandle(fd);
- HANDLE m;
- ev_uint64_t total_size = length+offset;
- if ((HANDLE)h == INVALID_HANDLE_VALUE)
- goto err;
- m = CreateFileMapping((HANDLE)h, NULL, PAGE_READONLY,
- (total_size >> 32), total_size & 0xfffffffful,
- NULL);
- if (m != INVALID_HANDLE_VALUE) { /* Does h leak? */
- seg->mapping_handle = m;
- seg->mmap_offset = offset;
- seg->is_mapping = 1;
- goto done;
- }
- }
-#endif
- {
- ev_off_t start_pos = lseek(fd, 0, SEEK_CUR), pos;
- ev_off_t read_so_far = 0;
- char *mem;
- int e;
- ev_ssize_t n = 0;
- if (!(mem = mm_malloc(length)))
- goto err;
- if (start_pos < 0) {
- mm_free(mem);
- goto err;
- }
- if (lseek(fd, offset, SEEK_SET) < 0) {
- mm_free(mem);
- goto err;
- }
- while (read_so_far < length) {
- n = read(fd, mem+read_so_far, length-read_so_far);
- if (n <= 0)
- break;
- read_so_far += n;
- }
-
- e = errno;
- pos = lseek(fd, start_pos, SEEK_SET);
- if (n < 0 || (n == 0 && length > read_so_far)) {
- mm_free(mem);
- errno = e;
- goto err;
- } else if (pos < 0) {
- mm_free(mem);
- goto err;
- }
-
- seg->contents = mem;
- }
-
-done:
- return 0;
-err:
- return -1;
-}
-
-void evbuffer_file_segment_add_cleanup_cb(struct evbuffer_file_segment *seg,
- evbuffer_file_segment_cleanup_cb cb, void* arg)
-{
- EVUTIL_ASSERT(seg->refcnt > 0);
- seg->cleanup_cb = cb;
- seg->cleanup_cb_arg = arg;
-}
-
-void
-evbuffer_file_segment_free(struct evbuffer_file_segment *seg)
-{
- int refcnt;
- EVLOCK_LOCK(seg->lock, 0);
- refcnt = --seg->refcnt;
- EVLOCK_UNLOCK(seg->lock, 0);
- if (refcnt > 0)
- return;
- EVUTIL_ASSERT(refcnt == 0);
-
- if (seg->is_mapping) {
-#ifdef _WIN32
- CloseHandle(seg->mapping_handle);
-#elif defined (EVENT__HAVE_MMAP)
- off_t offset_leftover;
- offset_leftover = seg->file_offset % get_page_size();
- if (munmap(seg->mapping, seg->length + offset_leftover) == -1)
- event_warn("%s: munmap failed", __func__);
-#endif
- } else if (seg->contents) {
- mm_free(seg->contents);
- }
-
- if ((seg->flags & EVBUF_FS_CLOSE_ON_FREE) && seg->fd >= 0) {
- close(seg->fd);
- }
-
- if (seg->cleanup_cb) {
- (*seg->cleanup_cb)((struct evbuffer_file_segment const*)seg,
- seg->flags, seg->cleanup_cb_arg);
- seg->cleanup_cb = NULL;
- seg->cleanup_cb_arg = NULL;
- }
-
- EVTHREAD_FREE_LOCK(seg->lock, 0);
- mm_free(seg);
-}
-
-int
-evbuffer_add_file_segment(struct evbuffer *buf,
- struct evbuffer_file_segment *seg, ev_off_t offset, ev_off_t length)
-{
- struct evbuffer_chain *chain;
- struct evbuffer_chain_file_segment *extra;
- int can_use_sendfile = 0;
-
- EVBUFFER_LOCK(buf);
- EVLOCK_LOCK(seg->lock, 0);
- if (buf->flags & EVBUFFER_FLAG_DRAINS_TO_FD) {
- can_use_sendfile = 1;
- } else {
- if (!seg->contents) {
- if (evbuffer_file_segment_materialize(seg)<0) {
- EVLOCK_UNLOCK(seg->lock, 0);
- EVBUFFER_UNLOCK(buf);
- return -1;
- }
- }
- }
- ++seg->refcnt;
- EVLOCK_UNLOCK(seg->lock, 0);
-
- if (buf->freeze_end)
- goto err;
-
- if (length < 0) {
- if (offset > seg->length)
- goto err;
- length = seg->length - offset;
- }
-
- /* Can we actually add this? */
- if (offset+length > seg->length)
- goto err;
-
- chain = evbuffer_chain_new(sizeof(struct evbuffer_chain_file_segment));
- if (!chain)
- goto err;
- extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_chain_file_segment, chain);
-
- chain->flags |= EVBUFFER_IMMUTABLE|EVBUFFER_FILESEGMENT;
- if (can_use_sendfile && seg->can_sendfile) {
- chain->flags |= EVBUFFER_SENDFILE;
- chain->misalign = seg->file_offset + offset;
- chain->off = length;
- chain->buffer_len = chain->misalign + length;
- } else if (seg->is_mapping) {
-#ifdef _WIN32
- ev_uint64_t total_offset = seg->mmap_offset+offset;
- ev_uint64_t offset_rounded=0, offset_remaining=0;
- LPVOID data;
- if (total_offset) {
- SYSTEM_INFO si;
- memset(&si, 0, sizeof(si)); /* cargo cult */
- GetSystemInfo(&si);
- offset_remaining = total_offset % si.dwAllocationGranularity;
- offset_rounded = total_offset - offset_remaining;
- }
- data = MapViewOfFile(
- seg->mapping_handle,
- FILE_MAP_READ,
- offset_rounded >> 32,
- offset_rounded & 0xfffffffful,
- length + offset_remaining);
- if (data == NULL) {
- mm_free(chain);
- goto err;
- }
- chain->buffer = (unsigned char*) data;
- chain->buffer_len = length+offset_remaining;
- chain->misalign = offset_remaining;
- chain->off = length;
-#else
- chain->buffer = (unsigned char*)(seg->contents + offset);
- chain->buffer_len = length;
- chain->off = length;
-#endif
- } else {
- chain->buffer = (unsigned char*)(seg->contents + offset);
- chain->buffer_len = length;
- chain->off = length;
- }
-
- extra->segment = seg;
- buf->n_add_for_cb += length;
- evbuffer_chain_insert(buf, chain);
-
- evbuffer_invoke_callbacks_(buf);
-
- EVBUFFER_UNLOCK(buf);
-
- return 0;
-err:
- EVBUFFER_UNLOCK(buf);
- evbuffer_file_segment_free(seg); /* Lowers the refcount */
- return -1;
-}
-
-int
-evbuffer_add_file(struct evbuffer *buf, int fd, ev_off_t offset, ev_off_t length)
-{
- struct evbuffer_file_segment *seg;
- unsigned flags = EVBUF_FS_CLOSE_ON_FREE;
- int r;
-
- seg = evbuffer_file_segment_new(fd, offset, length, flags);
- if (!seg)
- return -1;
- r = evbuffer_add_file_segment(buf, seg, 0, length);
- if (r == 0)
- evbuffer_file_segment_free(seg);
- return r;
-}
-
-void
-evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg)
-{
- EVBUFFER_LOCK(buffer);
-
- if (!LIST_EMPTY(&buffer->callbacks))
- evbuffer_remove_all_callbacks(buffer);
-
- if (cb) {
- struct evbuffer_cb_entry *ent =
- evbuffer_add_cb(buffer, NULL, cbarg);
- ent->cb.cb_obsolete = cb;
- ent->flags |= EVBUFFER_CB_OBSOLETE;
- }
- EVBUFFER_UNLOCK(buffer);
-}
-
-struct evbuffer_cb_entry *
-evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
-{
- struct evbuffer_cb_entry *e;
- if (! (e = mm_calloc(1, sizeof(struct evbuffer_cb_entry))))
- return NULL;
- EVBUFFER_LOCK(buffer);
- e->cb.cb_func = cb;
- e->cbarg = cbarg;
- e->flags = EVBUFFER_CB_ENABLED;
- LIST_INSERT_HEAD(&buffer->callbacks, e, next);
- EVBUFFER_UNLOCK(buffer);
- return e;
-}
-
-int
-evbuffer_remove_cb_entry(struct evbuffer *buffer,
- struct evbuffer_cb_entry *ent)
-{
- EVBUFFER_LOCK(buffer);
- LIST_REMOVE(ent, next);
- EVBUFFER_UNLOCK(buffer);
- mm_free(ent);
- return 0;
-}
-
-int
-evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg)
-{
- struct evbuffer_cb_entry *cbent;
- int result = -1;
- EVBUFFER_LOCK(buffer);
- LIST_FOREACH(cbent, &buffer->callbacks, next) {
- if (cb == cbent->cb.cb_func && cbarg == cbent->cbarg) {
- result = evbuffer_remove_cb_entry(buffer, cbent);
- goto done;
- }
- }
-done:
- EVBUFFER_UNLOCK(buffer);
- return result;
-}
-
-int
-evbuffer_cb_set_flags(struct evbuffer *buffer,
- struct evbuffer_cb_entry *cb, ev_uint32_t flags)
-{
- /* the user isn't allowed to mess with these. */
- flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
- EVBUFFER_LOCK(buffer);
- cb->flags |= flags;
- EVBUFFER_UNLOCK(buffer);
- return 0;
-}
-
-int
-evbuffer_cb_clear_flags(struct evbuffer *buffer,
- struct evbuffer_cb_entry *cb, ev_uint32_t flags)
-{
- /* the user isn't allowed to mess with these. */
- flags &= ~EVBUFFER_CB_INTERNAL_FLAGS;
- EVBUFFER_LOCK(buffer);
- cb->flags &= ~flags;
- EVBUFFER_UNLOCK(buffer);
- return 0;
-}
-
-int
-evbuffer_freeze(struct evbuffer *buffer, int start)
-{
- EVBUFFER_LOCK(buffer);
- if (start)
- buffer->freeze_start = 1;
- else
- buffer->freeze_end = 1;
- EVBUFFER_UNLOCK(buffer);
- return 0;
-}
-
-int
-evbuffer_unfreeze(struct evbuffer *buffer, int start)
-{
- EVBUFFER_LOCK(buffer);
- if (start)
- buffer->freeze_start = 0;
- else
- buffer->freeze_end = 0;
- EVBUFFER_UNLOCK(buffer);
- return 0;
-}
-
-#if 0
-void
-evbuffer_cb_suspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
-{
- if (!(cb->flags & EVBUFFER_CB_SUSPENDED)) {
- cb->size_before_suspend = evbuffer_get_length(buffer);
- cb->flags |= EVBUFFER_CB_SUSPENDED;
- }
-}
-
-void
-evbuffer_cb_unsuspend(struct evbuffer *buffer, struct evbuffer_cb_entry *cb)
-{
- if ((cb->flags & EVBUFFER_CB_SUSPENDED)) {
- unsigned call = (cb->flags & EVBUFFER_CB_CALL_ON_UNSUSPEND);
- size_t sz = cb->size_before_suspend;
- cb->flags &= ~(EVBUFFER_CB_SUSPENDED|
- EVBUFFER_CB_CALL_ON_UNSUSPEND);
- cb->size_before_suspend = 0;
- if (call && (cb->flags & EVBUFFER_CB_ENABLED)) {
- cb->cb(buffer, sz, evbuffer_get_length(buffer), cb->cbarg);
- }
- }
-}
-#endif
-
-int
-evbuffer_get_callbacks_(struct evbuffer *buffer, struct event_callback **cbs,
- int max_cbs)
-{
- int r = 0;
- EVBUFFER_LOCK(buffer);
- if (buffer->deferred_cbs) {
- if (max_cbs < 1) {
- r = -1;
- goto done;
- }
- cbs[0] = &buffer->deferred;
- r = 1;
- }
-done:
- EVBUFFER_UNLOCK(buffer);
- return r;
-}
diff --git a/libs/libevent/src/buffer_iocp.c b/libs/libevent/src/buffer_iocp.c
deleted file mode 100644
index 2d76a90e77..0000000000
--- a/libs/libevent/src/buffer_iocp.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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.
- */
-
-/**
- @file buffer_iocp.c
-
- This module implements overlapped read and write functions for evbuffer
- objects on Windows.
-*/
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include "event2/buffer.h"
-#include "event2/buffer_compat.h"
-#include "event2/util.h"
-#include "event2/thread.h"
-#include "util-internal.h"
-#include "evthread-internal.h"
-#include "evbuffer-internal.h"
-#include "iocp-internal.h"
-#include "mm-internal.h"
-
-#include <winsock2.h>
-#include <windows.h>
-#include <stdio.h>
-
-#define MAX_WSABUFS 16
-
-/** An evbuffer that can handle overlapped IO. */
-struct evbuffer_overlapped {
- struct evbuffer buffer;
- /** The socket that we're doing overlapped IO on. */
- evutil_socket_t fd;
-
- /** pending I/O type */
- unsigned read_in_progress : 1;
- unsigned write_in_progress : 1;
-
- /** The first pinned chain in the buffer. */
- struct evbuffer_chain *first_pinned;
-
- /** How many chains are pinned; how many of the fields in buffers
- * are we using. */
- int n_buffers;
- WSABUF buffers[MAX_WSABUFS];
-};
-
-/** Given an evbuffer, return the correponding evbuffer structure, or NULL if
- * the evbuffer isn't overlapped. */
-static inline struct evbuffer_overlapped *
-upcast_evbuffer(struct evbuffer *buf)
-{
- if (!buf || !buf->is_overlapped)
- return NULL;
- return EVUTIL_UPCAST(buf, struct evbuffer_overlapped, buffer);
-}
-
-/** Unpin all the chains noted as pinned in 'eo'. */
-static void
-pin_release(struct evbuffer_overlapped *eo, unsigned flag)
-{
- int i;
- struct evbuffer_chain *next, *chain = eo->first_pinned;
-
- for (i = 0; i < eo->n_buffers; ++i) {
- EVUTIL_ASSERT(chain);
- next = chain->next;
- evbuffer_chain_unpin_(chain, flag);
- chain = next;
- }
-}
-
-void
-evbuffer_commit_read_(struct evbuffer *evbuf, ev_ssize_t nBytes)
-{
- struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf);
- struct evbuffer_chain **chainp;
- size_t remaining, len;
- unsigned i;
-
- EVBUFFER_LOCK(evbuf);
- EVUTIL_ASSERT(buf->read_in_progress && !buf->write_in_progress);
- EVUTIL_ASSERT(nBytes >= 0); /* XXXX Can this be false? */
-
- evbuffer_unfreeze(evbuf, 0);
-
- chainp = evbuf->last_with_datap;
- if (!((*chainp)->flags & EVBUFFER_MEM_PINNED_R))
- chainp = &(*chainp)->next;
- remaining = nBytes;
- for (i = 0; remaining > 0 && i < (unsigned)buf->n_buffers; ++i) {
- EVUTIL_ASSERT(*chainp);
- len = buf->buffers[i].len;
- if (remaining < len)
- len = remaining;
- (*chainp)->off += len;
- evbuf->last_with_datap = chainp;
- remaining -= len;
- chainp = &(*chainp)->next;
- }
-
- pin_release(buf, EVBUFFER_MEM_PINNED_R);
-
- buf->read_in_progress = 0;
-
- evbuf->total_len += nBytes;
- evbuf->n_add_for_cb += nBytes;
-
- evbuffer_invoke_callbacks_(evbuf);
-
- evbuffer_decref_and_unlock_(evbuf);
-}
-
-void
-evbuffer_commit_write_(struct evbuffer *evbuf, ev_ssize_t nBytes)
-{
- struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf);
-
- EVBUFFER_LOCK(evbuf);
- EVUTIL_ASSERT(buf->write_in_progress && !buf->read_in_progress);
- evbuffer_unfreeze(evbuf, 1);
- evbuffer_drain(evbuf, nBytes);
- pin_release(buf,EVBUFFER_MEM_PINNED_W);
- buf->write_in_progress = 0;
- evbuffer_decref_and_unlock_(evbuf);
-}
-
-struct evbuffer *
-evbuffer_overlapped_new_(evutil_socket_t fd)
-{
- struct evbuffer_overlapped *evo;
-
- evo = mm_calloc(1, sizeof(struct evbuffer_overlapped));
- if (!evo)
- return NULL;
-
- LIST_INIT(&evo->buffer.callbacks);
- evo->buffer.refcnt = 1;
- evo->buffer.last_with_datap = &evo->buffer.first;
-
- evo->buffer.is_overlapped = 1;
- evo->fd = fd;
-
- return &evo->buffer;
-}
-
-int
-evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t at_most,
- struct event_overlapped *ol)
-{
- struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
- int r = -1;
- int i;
- struct evbuffer_chain *chain;
- DWORD bytesSent;
-
- if (!buf) {
- /* No buffer, or it isn't overlapped */
- return -1;
- }
-
- EVBUFFER_LOCK(buf);
- EVUTIL_ASSERT(!buf_o->read_in_progress);
- if (buf->freeze_start || buf_o->write_in_progress)
- goto done;
- if (!buf->total_len) {
- /* Nothing to write */
- r = 0;
- goto done;
- } else if (at_most < 0 || (size_t)at_most > buf->total_len) {
- at_most = buf->total_len;
- }
- evbuffer_freeze(buf, 1);
-
- buf_o->first_pinned = NULL;
- buf_o->n_buffers = 0;
- memset(buf_o->buffers, 0, sizeof(buf_o->buffers));
-
- chain = buf_o->first_pinned = buf->first;
-
- for (i=0; i < MAX_WSABUFS && chain; ++i, chain=chain->next) {
- WSABUF *b = &buf_o->buffers[i];
- b->buf = (char*)( chain->buffer + chain->misalign );
- evbuffer_chain_pin_(chain, EVBUFFER_MEM_PINNED_W);
-
- if ((size_t)at_most > chain->off) {
- /* XXXX Cast is safe for now, since win32 has no
- mmaped chains. But later, we need to have this
- add more WSAbufs if chain->off is greater than
- ULONG_MAX */
- b->len = (unsigned long)chain->off;
- at_most -= chain->off;
- } else {
- b->len = (unsigned long)at_most;
- ++i;
- break;
- }
- }
-
- buf_o->n_buffers = i;
- evbuffer_incref_(buf);
- if (WSASend(buf_o->fd, buf_o->buffers, i, &bytesSent, 0,
- &ol->overlapped, NULL)) {
- int error = WSAGetLastError();
- if (error != WSA_IO_PENDING) {
- /* An actual error. */
- pin_release(buf_o, EVBUFFER_MEM_PINNED_W);
- evbuffer_unfreeze(buf, 1);
- evbuffer_free(buf); /* decref */
- goto done;
- }
- }
-
- buf_o->write_in_progress = 1;
- r = 0;
-done:
- EVBUFFER_UNLOCK(buf);
- return r;
-}
-
-int
-evbuffer_launch_read_(struct evbuffer *buf, size_t at_most,
- struct event_overlapped *ol)
-{
- struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
- int r = -1, i;
- int nvecs;
- int npin=0;
- struct evbuffer_chain *chain=NULL, **chainp;
- DWORD bytesRead;
- DWORD flags = 0;
- struct evbuffer_iovec vecs[MAX_WSABUFS];
-
- if (!buf_o)
- return -1;
- EVBUFFER_LOCK(buf);
- EVUTIL_ASSERT(!buf_o->write_in_progress);
- if (buf->freeze_end || buf_o->read_in_progress)
- goto done;
-
- buf_o->first_pinned = NULL;
- buf_o->n_buffers = 0;
- memset(buf_o->buffers, 0, sizeof(buf_o->buffers));
-
- if (evbuffer_expand_fast_(buf, at_most, MAX_WSABUFS) == -1)
- goto done;
- evbuffer_freeze(buf, 0);
-
- nvecs = evbuffer_read_setup_vecs_(buf, at_most,
- vecs, MAX_WSABUFS, &chainp, 1);
- for (i=0;i<nvecs;++i) {
- WSABUF_FROM_EVBUFFER_IOV(
- &buf_o->buffers[i],
- &vecs[i]);
- }
-
- buf_o->n_buffers = nvecs;
- buf_o->first_pinned = chain = *chainp;
-
- npin=0;
- for ( ; chain; chain = chain->next) {
- evbuffer_chain_pin_(chain, EVBUFFER_MEM_PINNED_R);
- ++npin;
- }
- EVUTIL_ASSERT(npin == nvecs);
-
- evbuffer_incref_(buf);
- if (WSARecv(buf_o->fd, buf_o->buffers, nvecs, &bytesRead, &flags,
- &ol->overlapped, NULL)) {
- int error = WSAGetLastError();
- if (error != WSA_IO_PENDING) {
- /* An actual error. */
- pin_release(buf_o, EVBUFFER_MEM_PINNED_R);
- evbuffer_unfreeze(buf, 0);
- evbuffer_free(buf); /* decref */
- goto done;
- }
- }
-
- buf_o->read_in_progress = 1;
- r = 0;
-done:
- EVBUFFER_UNLOCK(buf);
- return r;
-}
-
-evutil_socket_t
-evbuffer_overlapped_get_fd_(struct evbuffer *buf)
-{
- struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
- return buf_o ? buf_o->fd : -1;
-}
-
-void
-evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd)
-{
- struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
- EVBUFFER_LOCK(buf);
- /* XXX is this right?, should it cancel current I/O operations? */
- if (buf_o)
- buf_o->fd = fd;
- EVBUFFER_UNLOCK(buf);
-}
diff --git a/libs/libevent/src/bufferevent-internal.h b/libs/libevent/src/bufferevent-internal.h
deleted file mode 100644
index d9d9e66640..0000000000
--- a/libs/libevent/src/bufferevent-internal.h
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Copyright (c) 2008-2012 Niels Provos and Nick Mathewson
- *
- * 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 BUFFEREVENT_INTERNAL_H_INCLUDED_
-#define BUFFEREVENT_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/event-config.h"
-#include "event2/event_struct.h"
-#include "evconfig-private.h"
-#include "event2/util.h"
-#include "defer-internal.h"
-#include "evthread-internal.h"
-#include "event2/thread.h"
-#include "ratelim-internal.h"
-#include "event2/bufferevent_struct.h"
-
-#include "ipv6-internal.h"
-#ifdef _WIN32
-#include <ws2tcpip.h>
-#endif
-#ifdef EVENT__HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef EVENT__HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-
-/* These flags are reasons that we might be declining to actually enable
- reading or writing on a bufferevent.
- */
-
-/* On a all bufferevents, for reading: used when we have read up to the
- watermark value.
-
- On a filtering bufferevent, for writing: used when the underlying
- bufferevent's write buffer has been filled up to its watermark
- value.
-*/
-#define BEV_SUSPEND_WM 0x01
-/* On a base bufferevent: when we have emptied a bandwidth buckets */
-#define BEV_SUSPEND_BW 0x02
-/* On a base bufferevent: when we have emptied the group's bandwidth bucket. */
-#define BEV_SUSPEND_BW_GROUP 0x04
-/* On a socket bufferevent: can't do any operations while we're waiting for
- * name lookup to finish. */
-#define BEV_SUSPEND_LOOKUP 0x08
-/* On a base bufferevent, for reading: used when a filter has choked this
- * (underlying) bufferevent because it has stopped reading from it. */
-#define BEV_SUSPEND_FILT_READ 0x10
-
-typedef ev_uint16_t bufferevent_suspend_flags;
-
-struct bufferevent_rate_limit_group {
- /** List of all members in the group */
- LIST_HEAD(rlim_group_member_list, bufferevent_private) members;
- /** Current limits for the group. */
- struct ev_token_bucket rate_limit;
- struct ev_token_bucket_cfg rate_limit_cfg;
-
- /** True iff we don't want to read from any member of the group.until
- * the token bucket refills. */
- unsigned read_suspended : 1;
- /** True iff we don't want to write from any member of the group.until
- * the token bucket refills. */
- unsigned write_suspended : 1;
- /** True iff we were unable to suspend one of the bufferevents in the
- * group for reading the last time we tried, and we should try
- * again. */
- unsigned pending_unsuspend_read : 1;
- /** True iff we were unable to suspend one of the bufferevents in the
- * group for writing the last time we tried, and we should try
- * again. */
- unsigned pending_unsuspend_write : 1;
-
- /*@{*/
- /** Total number of bytes read or written in this group since last
- * reset. */
- ev_uint64_t total_read;
- ev_uint64_t total_written;
- /*@}*/
-
- /** The number of bufferevents in the group. */
- int n_members;
-
- /** The smallest number of bytes that any member of the group should
- * be limited to read or write at a time. */
- ev_ssize_t min_share;
- ev_ssize_t configured_min_share;
-
- /** Timeout event that goes off once a tick, when the bucket is ready
- * to refill. */
- struct event master_refill_event;
-
- /** Seed for weak random number generator. Protected by 'lock' */
- struct evutil_weakrand_state weakrand_seed;
-
- /** Lock to protect the members of this group. This lock should nest
- * within every bufferevent lock: if you are holding this lock, do
- * not assume you can lock another bufferevent. */
- void *lock;
-};
-
-/** Fields for rate-limiting a single bufferevent. */
-struct bufferevent_rate_limit {
- /* Linked-list elements for storing this bufferevent_private in a
- * group.
- *
- * Note that this field is supposed to be protected by the group
- * lock */
- LIST_ENTRY(bufferevent_private) next_in_group;
- /** The rate-limiting group for this bufferevent, or NULL if it is
- * only rate-limited on its own. */
- struct bufferevent_rate_limit_group *group;
-
- /* This bufferevent's current limits. */
- struct ev_token_bucket limit;
- /* Pointer to the rate-limit configuration for this bufferevent.
- * Can be shared. XXX reference-count this? */
- struct ev_token_bucket_cfg *cfg;
-
- /* Timeout event used when one this bufferevent's buckets are
- * empty. */
- struct event refill_bucket_event;
-};
-
-/** Parts of the bufferevent structure that are shared among all bufferevent
- * types, but not exposed in bufferevent_struct.h. */
-struct bufferevent_private {
- /** The underlying bufferevent structure. */
- struct bufferevent bev;
-
- /** Evbuffer callback to enforce watermarks on input. */
- struct evbuffer_cb_entry *read_watermarks_cb;
-
- /** If set, we should free the lock when we free the bufferevent. */
- unsigned own_lock : 1;
-
- /** Flag: set if we have deferred callbacks and a read callback is
- * pending. */
- unsigned readcb_pending : 1;
- /** Flag: set if we have deferred callbacks and a write callback is
- * pending. */
- unsigned writecb_pending : 1;
- /** Flag: set if we are currently busy connecting. */
- unsigned connecting : 1;
- /** Flag: set if a connect failed prematurely; this is a hack for
- * getting around the bufferevent abstraction. */
- unsigned connection_refused : 1;
- /** Set to the events pending if we have deferred callbacks and
- * an events callback is pending. */
- short eventcb_pending;
-
- /** If set, read is suspended until one or more conditions are over.
- * The actual value here is a bitfield of those conditions; see the
- * BEV_SUSPEND_* flags above. */
- bufferevent_suspend_flags read_suspended;
-
- /** If set, writing is suspended until one or more conditions are over.
- * The actual value here is a bitfield of those conditions; see the
- * BEV_SUSPEND_* flags above. */
- bufferevent_suspend_flags write_suspended;
-
- /** Set to the current socket errno if we have deferred callbacks and
- * an events callback is pending. */
- int errno_pending;
-
- /** The DNS error code for bufferevent_socket_connect_hostname */
- int dns_error;
-
- /** Used to implement deferred callbacks */
- struct event_callback deferred;
-
- /** The options this bufferevent was constructed with */
- enum bufferevent_options options;
-
- /** Current reference count for this bufferevent. */
- int refcnt;
-
- /** Lock for this bufferevent. Shared by the inbuf and the outbuf.
- * If NULL, locking is disabled. */
- void *lock;
-
- /** No matter how big our bucket gets, don't try to read more than this
- * much in a single read operation. */
- ev_ssize_t max_single_read;
-
- /** No matter how big our bucket gets, don't try to write more than this
- * much in a single write operation. */
- ev_ssize_t max_single_write;
-
- /** Rate-limiting information for this bufferevent */
- struct bufferevent_rate_limit *rate_limiting;
-
- /* Saved conn_addr, to extract IP address from it.
- *
- * Because some servers may reset/close connection without waiting clients,
- * in that case we can't extract IP address even in close_cb.
- * So we need to save it, just after we connected to remote server, or
- * after resolving (to avoid extra dns requests during retrying, since UDP
- * is slow) */
- union {
- struct sockaddr_in6 in6;
- struct sockaddr_in in;
- } conn_address;
-};
-
-/** Possible operations for a control callback. */
-enum bufferevent_ctrl_op {
- BEV_CTRL_SET_FD,
- BEV_CTRL_GET_FD,
- BEV_CTRL_GET_UNDERLYING,
- BEV_CTRL_CANCEL_ALL
-};
-
-/** Possible data types for a control callback */
-union bufferevent_ctrl_data {
- void *ptr;
- evutil_socket_t fd;
-};
-
-/**
- Implementation table for a bufferevent: holds function pointers and other
- information to make the various bufferevent types work.
-*/
-struct bufferevent_ops {
- /** The name of the bufferevent's type. */
- const char *type;
- /** At what offset into the implementation type will we find a
- bufferevent structure?
-
- Example: if the type is implemented as
- struct bufferevent_x {
- int extra_data;
- struct bufferevent bev;
- }
- then mem_offset should be offsetof(struct bufferevent_x, bev)
- */
- off_t mem_offset;
-
- /** Enables one or more of EV_READ|EV_WRITE on a bufferevent. Does
- not need to adjust the 'enabled' field. Returns 0 on success, -1
- on failure.
- */
- int (*enable)(struct bufferevent *, short);
-
- /** Disables one or more of EV_READ|EV_WRITE on a bufferevent. Does
- not need to adjust the 'enabled' field. Returns 0 on success, -1
- on failure.
- */
- int (*disable)(struct bufferevent *, short);
-
- /** Detatches the bufferevent from related data structures. Called as
- * soon as its reference count reaches 0. */
- void (*unlink)(struct bufferevent *);
-
- /** Free any storage and deallocate any extra data or structures used
- in this implementation. Called when the bufferevent is
- finalized.
- */
- void (*destruct)(struct bufferevent *);
-
- /** Called when the timeouts on the bufferevent have changed.*/
- int (*adj_timeouts)(struct bufferevent *);
-
- /** Called to flush data. */
- int (*flush)(struct bufferevent *, short, enum bufferevent_flush_mode);
-
- /** Called to access miscellaneous fields. */
- int (*ctrl)(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
-
-};
-
-extern const struct bufferevent_ops bufferevent_ops_socket;
-extern const struct bufferevent_ops bufferevent_ops_filter;
-extern const struct bufferevent_ops bufferevent_ops_pair;
-
-#define BEV_IS_SOCKET(bevp) ((bevp)->be_ops == &bufferevent_ops_socket)
-#define BEV_IS_FILTER(bevp) ((bevp)->be_ops == &bufferevent_ops_filter)
-#define BEV_IS_PAIR(bevp) ((bevp)->be_ops == &bufferevent_ops_pair)
-
-#ifdef _WIN32
-extern const struct bufferevent_ops bufferevent_ops_async;
-#define BEV_IS_ASYNC(bevp) ((bevp)->be_ops == &bufferevent_ops_async)
-#else
-#define BEV_IS_ASYNC(bevp) 0
-#endif
-
-/** Initialize the shared parts of a bufferevent. */
-int bufferevent_init_common_(struct bufferevent_private *, struct event_base *, const struct bufferevent_ops *, enum bufferevent_options options);
-
-/** For internal use: temporarily stop all reads on bufev, until the conditions
- * in 'what' are over. */
-void bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what);
-/** For internal use: clear the conditions 'what' on bufev, and re-enable
- * reading if there are no conditions left. */
-void bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what);
-
-/** For internal use: temporarily stop all writes on bufev, until the conditions
- * in 'what' are over. */
-void bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what);
-/** For internal use: clear the conditions 'what' on bufev, and re-enable
- * writing if there are no conditions left. */
-void bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what);
-
-#define bufferevent_wm_suspend_read(b) \
- bufferevent_suspend_read_((b), BEV_SUSPEND_WM)
-#define bufferevent_wm_unsuspend_read(b) \
- bufferevent_unsuspend_read_((b), BEV_SUSPEND_WM)
-
-/*
- Disable a bufferevent. Equivalent to bufferevent_disable(), but
- first resets 'connecting' flag to force EV_WRITE down for sure.
-
- XXXX this method will go away in the future; try not to add new users.
- See comment in evhttp_connection_reset_() for discussion.
-
- @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_disable()
- */
-int bufferevent_disable_hard_(struct bufferevent *bufev, short event);
-
-/** Internal: Set up locking on a bufferevent. If lock is set, use it.
- * Otherwise, use a new lock. */
-int bufferevent_enable_locking_(struct bufferevent *bufev, void *lock);
-/** Internal: backwards compat macro for the now public function
- * Increment the reference count on bufev. */
-#define bufferevent_incref_(bufev) bufferevent_incref(bufev)
-/** Internal: Lock bufev and increase its reference count.
- * unlocking it otherwise. */
-void bufferevent_incref_and_lock_(struct bufferevent *bufev);
-/** Internal: backwards compat macro for the now public function
- * Decrement the reference count on bufev. Returns 1 if it freed
- * the bufferevent.*/
-#define bufferevent_decref_(bufev) bufferevent_decref(bufev)
-
-/** Internal: Drop the reference count on bufev, freeing as necessary, and
- * unlocking it otherwise. Returns 1 if it freed the bufferevent. */
-int bufferevent_decref_and_unlock_(struct bufferevent *bufev);
-
-/** Internal: If callbacks are deferred and we have a read callback, schedule
- * a readcb. Otherwise just run the readcb. Ignores watermarks. */
-void bufferevent_run_readcb_(struct bufferevent *bufev, int options);
-/** Internal: If callbacks are deferred and we have a write callback, schedule
- * a writecb. Otherwise just run the writecb. Ignores watermarks. */
-void bufferevent_run_writecb_(struct bufferevent *bufev, int options);
-/** Internal: If callbacks are deferred and we have an eventcb, schedule
- * it to run with events "what". Otherwise just run the eventcb.
- * See bufferevent_trigger_event for meaning of "options". */
-void bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options);
-
-/** Internal: Run or schedule (if deferred or options contain
- * BEV_TRIG_DEFER_CALLBACKS) I/O callbacks specified in iotype.
- * Must already hold the bufev lock. Honors watermarks unless
- * BEV_TRIG_IGNORE_WATERMARKS is in options. */
-static inline void bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options);
-
-/* Making this inline since all of the common-case calls to this function in
- * libevent use constant arguments. */
-static inline void
-bufferevent_trigger_nolock_(struct bufferevent *bufev, short iotype, int options)
-{
- if ((iotype & EV_READ) && ((options & BEV_TRIG_IGNORE_WATERMARKS) ||
- evbuffer_get_length(bufev->input) >= bufev->wm_read.low))
- bufferevent_run_readcb_(bufev, options);
- if ((iotype & EV_WRITE) && ((options & BEV_TRIG_IGNORE_WATERMARKS) ||
- evbuffer_get_length(bufev->output) <= bufev->wm_write.low))
- bufferevent_run_writecb_(bufev, options);
-}
-
-/** Internal: Add the event 'ev' with timeout tv, unless tv is set to 0, in
- * which case add ev with no timeout. */
-int bufferevent_add_event_(struct event *ev, const struct timeval *tv);
-
-/* =========
- * These next functions implement timeouts for bufferevents that aren't doing
- * anything else with ev_read and ev_write, to handle timeouts.
- * ========= */
-/** Internal use: Set up the ev_read and ev_write callbacks so that
- * the other "generic_timeout" functions will work on it. Call this from
- * the constructor function. */
-void bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev);
-/** Internal use: Add or delete the generic timeout events as appropriate.
- * (If an event is enabled and a timeout is set, we add the event. Otherwise
- * we delete it.) Call this from anything that changes the timeout values,
- * that enabled EV_READ or EV_WRITE, or that disables EV_READ or EV_WRITE. */
-int bufferevent_generic_adj_timeouts_(struct bufferevent *bev);
-int bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev);
-
-enum bufferevent_options bufferevent_get_options_(struct bufferevent *bev);
-
-const struct sockaddr*
-bufferevent_socket_get_conn_address_(struct bufferevent *bev);
-
-/** Internal use: We have just successfully read data into an inbuf, so
- * reset the read timeout (if any). */
-#define BEV_RESET_GENERIC_READ_TIMEOUT(bev) \
- do { \
- if (evutil_timerisset(&(bev)->timeout_read)) \
- event_add(&(bev)->ev_read, &(bev)->timeout_read); \
- } while (0)
-/** Internal use: We have just successfully written data from an inbuf, so
- * reset the read timeout (if any). */
-#define BEV_RESET_GENERIC_WRITE_TIMEOUT(bev) \
- do { \
- if (evutil_timerisset(&(bev)->timeout_write)) \
- event_add(&(bev)->ev_write, &(bev)->timeout_write); \
- } while (0)
-#define BEV_DEL_GENERIC_READ_TIMEOUT(bev) \
- event_del(&(bev)->ev_read)
-#define BEV_DEL_GENERIC_WRITE_TIMEOUT(bev) \
- event_del(&(bev)->ev_write)
-
-
-/** Internal: Given a bufferevent, return its corresponding
- * bufferevent_private. */
-#define BEV_UPCAST(b) EVUTIL_UPCAST((b), struct bufferevent_private, bev)
-
-#ifdef EVENT__DISABLE_THREAD_SUPPORT
-#define BEV_LOCK(b) EVUTIL_NIL_STMT_
-#define BEV_UNLOCK(b) EVUTIL_NIL_STMT_
-#else
-/** Internal: Grab the lock (if any) on a bufferevent */
-#define BEV_LOCK(b) do { \
- struct bufferevent_private *locking = BEV_UPCAST(b); \
- EVLOCK_LOCK(locking->lock, 0); \
- } while (0)
-
-/** Internal: Release the lock (if any) on a bufferevent */
-#define BEV_UNLOCK(b) do { \
- struct bufferevent_private *locking = BEV_UPCAST(b); \
- EVLOCK_UNLOCK(locking->lock, 0); \
- } while (0)
-#endif
-
-
-/* ==== For rate-limiting. */
-
-int bufferevent_decrement_write_buckets_(struct bufferevent_private *bev,
- ev_ssize_t bytes);
-int bufferevent_decrement_read_buckets_(struct bufferevent_private *bev,
- ev_ssize_t bytes);
-ev_ssize_t bufferevent_get_read_max_(struct bufferevent_private *bev);
-ev_ssize_t bufferevent_get_write_max_(struct bufferevent_private *bev);
-
-int bufferevent_ratelim_init_(struct bufferevent_private *bev);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* BUFFEREVENT_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/bufferevent.c b/libs/libevent/src/bufferevent.c
deleted file mode 100644
index 59ae24f143..0000000000
--- a/libs/libevent/src/bufferevent.c
+++ /dev/null
@@ -1,1016 +0,0 @@
-/*
- * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos, Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-#include <errno.h>
-
-#include "event2/util.h"
-#include "event2/buffer.h"
-#include "event2/buffer_compat.h"
-#include "event2/bufferevent.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/bufferevent_compat.h"
-#include "event2/event.h"
-#include "event-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "bufferevent-internal.h"
-#include "evbuffer-internal.h"
-#include "util-internal.h"
-
-static void bufferevent_cancel_all_(struct bufferevent *bev);
-static void bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_);
-
-void
-bufferevent_suspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- BEV_LOCK(bufev);
- if (!bufev_private->read_suspended)
- bufev->be_ops->disable(bufev, EV_READ);
- bufev_private->read_suspended |= what;
- BEV_UNLOCK(bufev);
-}
-
-void
-bufferevent_unsuspend_read_(struct bufferevent *bufev, bufferevent_suspend_flags what)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- BEV_LOCK(bufev);
- bufev_private->read_suspended &= ~what;
- if (!bufev_private->read_suspended && (bufev->enabled & EV_READ))
- bufev->be_ops->enable(bufev, EV_READ);
- BEV_UNLOCK(bufev);
-}
-
-void
-bufferevent_suspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- BEV_LOCK(bufev);
- if (!bufev_private->write_suspended)
- bufev->be_ops->disable(bufev, EV_WRITE);
- bufev_private->write_suspended |= what;
- BEV_UNLOCK(bufev);
-}
-
-void
-bufferevent_unsuspend_write_(struct bufferevent *bufev, bufferevent_suspend_flags what)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- BEV_LOCK(bufev);
- bufev_private->write_suspended &= ~what;
- if (!bufev_private->write_suspended && (bufev->enabled & EV_WRITE))
- bufev->be_ops->enable(bufev, EV_WRITE);
- BEV_UNLOCK(bufev);
-}
-
-
-/* Callback to implement watermarks on the input buffer. Only enabled
- * if the watermark is set. */
-static void
-bufferevent_inbuf_wm_cb(struct evbuffer *buf,
- const struct evbuffer_cb_info *cbinfo,
- void *arg)
-{
- struct bufferevent *bufev = arg;
- size_t size;
-
- size = evbuffer_get_length(buf);
-
- if (size >= bufev->wm_read.high)
- bufferevent_wm_suspend_read(bufev);
- else
- bufferevent_wm_unsuspend_read(bufev);
-}
-
-static void
-bufferevent_run_deferred_callbacks_locked(struct event_callback *cb, void *arg)
-{
- struct bufferevent_private *bufev_private = arg;
- struct bufferevent *bufev = &bufev_private->bev;
-
- BEV_LOCK(bufev);
- if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
- bufev->errorcb) {
- /* The "connected" happened before any reads or writes, so
- send it first. */
- bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
- bufev->errorcb(bufev, BEV_EVENT_CONNECTED, bufev->cbarg);
- }
- if (bufev_private->readcb_pending && bufev->readcb) {
- bufev_private->readcb_pending = 0;
- bufev->readcb(bufev, bufev->cbarg);
- }
- if (bufev_private->writecb_pending && bufev->writecb) {
- bufev_private->writecb_pending = 0;
- bufev->writecb(bufev, bufev->cbarg);
- }
- if (bufev_private->eventcb_pending && bufev->errorcb) {
- short what = bufev_private->eventcb_pending;
- int err = bufev_private->errno_pending;
- bufev_private->eventcb_pending = 0;
- bufev_private->errno_pending = 0;
- EVUTIL_SET_SOCKET_ERROR(err);
- bufev->errorcb(bufev, what, bufev->cbarg);
- }
- bufferevent_decref_and_unlock_(bufev);
-}
-
-static void
-bufferevent_run_deferred_callbacks_unlocked(struct event_callback *cb, void *arg)
-{
- struct bufferevent_private *bufev_private = arg;
- struct bufferevent *bufev = &bufev_private->bev;
-
- BEV_LOCK(bufev);
-#define UNLOCKED(stmt) \
- do { BEV_UNLOCK(bufev); stmt; BEV_LOCK(bufev); } while(0)
-
- if ((bufev_private->eventcb_pending & BEV_EVENT_CONNECTED) &&
- bufev->errorcb) {
- /* The "connected" happened before any reads or writes, so
- send it first. */
- bufferevent_event_cb errorcb = bufev->errorcb;
- void *cbarg = bufev->cbarg;
- bufev_private->eventcb_pending &= ~BEV_EVENT_CONNECTED;
- UNLOCKED(errorcb(bufev, BEV_EVENT_CONNECTED, cbarg));
- }
- if (bufev_private->readcb_pending && bufev->readcb) {
- bufferevent_data_cb readcb = bufev->readcb;
- void *cbarg = bufev->cbarg;
- bufev_private->readcb_pending = 0;
- UNLOCKED(readcb(bufev, cbarg));
- }
- if (bufev_private->writecb_pending && bufev->writecb) {
- bufferevent_data_cb writecb = bufev->writecb;
- void *cbarg = bufev->cbarg;
- bufev_private->writecb_pending = 0;
- UNLOCKED(writecb(bufev, cbarg));
- }
- if (bufev_private->eventcb_pending && bufev->errorcb) {
- bufferevent_event_cb errorcb = bufev->errorcb;
- void *cbarg = bufev->cbarg;
- short what = bufev_private->eventcb_pending;
- int err = bufev_private->errno_pending;
- bufev_private->eventcb_pending = 0;
- bufev_private->errno_pending = 0;
- EVUTIL_SET_SOCKET_ERROR(err);
- UNLOCKED(errorcb(bufev,what,cbarg));
- }
- bufferevent_decref_and_unlock_(bufev);
-#undef UNLOCKED
-}
-
-#define SCHEDULE_DEFERRED(bevp) \
- do { \
- if (event_deferred_cb_schedule_( \
- (bevp)->bev.ev_base, \
- &(bevp)->deferred)) \
- bufferevent_incref_(&(bevp)->bev); \
- } while (0)
-
-
-void
-bufferevent_run_readcb_(struct bufferevent *bufev, int options)
-{
- /* Requires that we hold the lock and a reference */
- struct bufferevent_private *p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- if (bufev->readcb == NULL)
- return;
- if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
- p->readcb_pending = 1;
- SCHEDULE_DEFERRED(p);
- } else {
- bufev->readcb(bufev, bufev->cbarg);
- }
-}
-
-void
-bufferevent_run_writecb_(struct bufferevent *bufev, int options)
-{
- /* Requires that we hold the lock and a reference */
- struct bufferevent_private *p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- if (bufev->writecb == NULL)
- return;
- if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
- p->writecb_pending = 1;
- SCHEDULE_DEFERRED(p);
- } else {
- bufev->writecb(bufev, bufev->cbarg);
- }
-}
-
-#define BEV_TRIG_ALL_OPTS ( \
- BEV_TRIG_IGNORE_WATERMARKS| \
- BEV_TRIG_DEFER_CALLBACKS \
- )
-
-void
-bufferevent_trigger(struct bufferevent *bufev, short iotype, int options)
-{
- bufferevent_incref_and_lock_(bufev);
- bufferevent_trigger_nolock_(bufev, iotype, options&BEV_TRIG_ALL_OPTS);
- bufferevent_decref_and_unlock_(bufev);
-}
-
-void
-bufferevent_run_eventcb_(struct bufferevent *bufev, short what, int options)
-{
- /* Requires that we hold the lock and a reference */
- struct bufferevent_private *p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- if (bufev->errorcb == NULL)
- return;
- if ((p->options|options) & BEV_OPT_DEFER_CALLBACKS) {
- p->eventcb_pending |= what;
- p->errno_pending = EVUTIL_SOCKET_ERROR();
- SCHEDULE_DEFERRED(p);
- } else {
- bufev->errorcb(bufev, what, bufev->cbarg);
- }
-}
-
-void
-bufferevent_trigger_event(struct bufferevent *bufev, short what, int options)
-{
- bufferevent_incref_and_lock_(bufev);
- bufferevent_run_eventcb_(bufev, what, options&BEV_TRIG_ALL_OPTS);
- bufferevent_decref_and_unlock_(bufev);
-}
-
-int
-bufferevent_init_common_(struct bufferevent_private *bufev_private,
- struct event_base *base,
- const struct bufferevent_ops *ops,
- enum bufferevent_options options)
-{
- struct bufferevent *bufev = &bufev_private->bev;
-
- if (!bufev->input) {
- if ((bufev->input = evbuffer_new()) == NULL)
- return -1;
- }
-
- if (!bufev->output) {
- if ((bufev->output = evbuffer_new()) == NULL) {
- evbuffer_free(bufev->input);
- return -1;
- }
- }
-
- bufev_private->refcnt = 1;
- bufev->ev_base = base;
-
- /* Disable timeouts. */
- evutil_timerclear(&bufev->timeout_read);
- evutil_timerclear(&bufev->timeout_write);
-
- bufev->be_ops = ops;
-
- bufferevent_ratelim_init_(bufev_private);
-
- /*
- * 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;
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (options & BEV_OPT_THREADSAFE) {
- if (bufferevent_enable_locking_(bufev, NULL) < 0) {
- /* cleanup */
- evbuffer_free(bufev->input);
- evbuffer_free(bufev->output);
- bufev->input = NULL;
- bufev->output = NULL;
- return -1;
- }
- }
-#endif
- if ((options & (BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS))
- == BEV_OPT_UNLOCK_CALLBACKS) {
- event_warnx("UNLOCK_CALLBACKS requires DEFER_CALLBACKS");
- return -1;
- }
- if (options & BEV_OPT_UNLOCK_CALLBACKS)
- event_deferred_cb_init_(
- &bufev_private->deferred,
- event_base_get_npriorities(base) / 2,
- bufferevent_run_deferred_callbacks_unlocked,
- bufev_private);
- else
- event_deferred_cb_init_(
- &bufev_private->deferred,
- event_base_get_npriorities(base) / 2,
- bufferevent_run_deferred_callbacks_locked,
- bufev_private);
-
- bufev_private->options = options;
-
- evbuffer_set_parent_(bufev->input, bufev);
- evbuffer_set_parent_(bufev->output, bufev);
-
- return 0;
-}
-
-void
-bufferevent_setcb(struct bufferevent *bufev,
- bufferevent_data_cb readcb, bufferevent_data_cb writecb,
- bufferevent_event_cb eventcb, void *cbarg)
-{
- BEV_LOCK(bufev);
-
- bufev->readcb = readcb;
- bufev->writecb = writecb;
- bufev->errorcb = eventcb;
-
- bufev->cbarg = cbarg;
- BEV_UNLOCK(bufev);
-}
-
-void
-bufferevent_getcb(struct bufferevent *bufev,
- bufferevent_data_cb *readcb_ptr,
- bufferevent_data_cb *writecb_ptr,
- bufferevent_event_cb *eventcb_ptr,
- void **cbarg_ptr)
-{
- BEV_LOCK(bufev);
- if (readcb_ptr)
- *readcb_ptr = bufev->readcb;
- if (writecb_ptr)
- *writecb_ptr = bufev->writecb;
- if (eventcb_ptr)
- *eventcb_ptr = bufev->errorcb;
- if (cbarg_ptr)
- *cbarg_ptr = bufev->cbarg;
-
- BEV_UNLOCK(bufev);
-}
-
-struct evbuffer *
-bufferevent_get_input(struct bufferevent *bufev)
-{
- return bufev->input;
-}
-
-struct evbuffer *
-bufferevent_get_output(struct bufferevent *bufev)
-{
- return bufev->output;
-}
-
-struct event_base *
-bufferevent_get_base(struct bufferevent *bufev)
-{
- return bufev->ev_base;
-}
-
-int
-bufferevent_get_priority(const struct bufferevent *bufev)
-{
- if (event_initialized(&bufev->ev_read)) {
- return event_get_priority(&bufev->ev_read);
- } else {
- return event_base_get_npriorities(bufev->ev_base) / 2;
- }
-}
-
-int
-bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
-{
- if (evbuffer_add(bufev->output, data, size) == -1)
- return (-1);
-
- return 0;
-}
-
-int
-bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
-{
- if (evbuffer_add_buffer(bufev->output, buf) == -1)
- return (-1);
-
- return 0;
-}
-
-size_t
-bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
-{
- return (evbuffer_remove(bufev->input, data, size));
-}
-
-int
-bufferevent_read_buffer(struct bufferevent *bufev, struct evbuffer *buf)
-{
- return (evbuffer_add_buffer(buf, bufev->input));
-}
-
-int
-bufferevent_enable(struct bufferevent *bufev, short event)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- short impl_events = event;
- int r = 0;
-
- bufferevent_incref_and_lock_(bufev);
- if (bufev_private->read_suspended)
- impl_events &= ~EV_READ;
- if (bufev_private->write_suspended)
- impl_events &= ~EV_WRITE;
-
- bufev->enabled |= event;
-
- if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)
- r = -1;
-
- bufferevent_decref_and_unlock_(bufev);
- return r;
-}
-
-int
-bufferevent_set_timeouts(struct bufferevent *bufev,
- const struct timeval *tv_read,
- const struct timeval *tv_write)
-{
- int r = 0;
- BEV_LOCK(bufev);
- if (tv_read) {
- bufev->timeout_read = *tv_read;
- } else {
- evutil_timerclear(&bufev->timeout_read);
- }
- if (tv_write) {
- bufev->timeout_write = *tv_write;
- } else {
- evutil_timerclear(&bufev->timeout_write);
- }
-
- if (bufev->be_ops->adj_timeouts)
- r = bufev->be_ops->adj_timeouts(bufev);
- BEV_UNLOCK(bufev);
-
- return r;
-}
-
-
-/* Obsolete; use bufferevent_set_timeouts */
-void
-bufferevent_settimeout(struct bufferevent *bufev,
- int timeout_read, int timeout_write)
-{
- struct timeval tv_read, tv_write;
- struct timeval *ptv_read = NULL, *ptv_write = NULL;
-
- memset(&tv_read, 0, sizeof(tv_read));
- memset(&tv_write, 0, sizeof(tv_write));
-
- if (timeout_read) {
- tv_read.tv_sec = timeout_read;
- ptv_read = &tv_read;
- }
- if (timeout_write) {
- tv_write.tv_sec = timeout_write;
- ptv_write = &tv_write;
- }
-
- bufferevent_set_timeouts(bufev, ptv_read, ptv_write);
-}
-
-
-int
-bufferevent_disable_hard_(struct bufferevent *bufev, short event)
-{
- int r = 0;
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
-
- BEV_LOCK(bufev);
- bufev->enabled &= ~event;
-
- bufev_private->connecting = 0;
- if (bufev->be_ops->disable(bufev, event) < 0)
- r = -1;
-
- BEV_UNLOCK(bufev);
- return r;
-}
-
-int
-bufferevent_disable(struct bufferevent *bufev, short event)
-{
- int r = 0;
-
- BEV_LOCK(bufev);
- bufev->enabled &= ~event;
-
- if (bufev->be_ops->disable(bufev, event) < 0)
- r = -1;
-
- BEV_UNLOCK(bufev);
- return r;
-}
-
-/*
- * Sets the water marks
- */
-
-void
-bufferevent_setwatermark(struct bufferevent *bufev, short events,
- size_t lowmark, size_t highmark)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
-
- BEV_LOCK(bufev);
- if (events & EV_WRITE) {
- bufev->wm_write.low = lowmark;
- bufev->wm_write.high = highmark;
- }
-
- if (events & EV_READ) {
- bufev->wm_read.low = lowmark;
- bufev->wm_read.high = highmark;
-
- if (highmark) {
- /* There is now a new high-water mark for read.
- enable the callback if needed, and see if we should
- suspend/bufferevent_wm_unsuspend. */
-
- if (bufev_private->read_watermarks_cb == NULL) {
- bufev_private->read_watermarks_cb =
- evbuffer_add_cb(bufev->input,
- bufferevent_inbuf_wm_cb,
- bufev);
- }
- evbuffer_cb_set_flags(bufev->input,
- bufev_private->read_watermarks_cb,
- EVBUFFER_CB_ENABLED|EVBUFFER_CB_NODEFER);
-
- if (evbuffer_get_length(bufev->input) >= highmark)
- bufferevent_wm_suspend_read(bufev);
- else if (evbuffer_get_length(bufev->input) < highmark)
- bufferevent_wm_unsuspend_read(bufev);
- } else {
- /* There is now no high-water mark for read. */
- if (bufev_private->read_watermarks_cb)
- evbuffer_cb_clear_flags(bufev->input,
- bufev_private->read_watermarks_cb,
- EVBUFFER_CB_ENABLED);
- bufferevent_wm_unsuspend_read(bufev);
- }
- }
- BEV_UNLOCK(bufev);
-}
-
-int
-bufferevent_getwatermark(struct bufferevent *bufev, short events,
- size_t *lowmark, size_t *highmark)
-{
- if (events == EV_WRITE) {
- BEV_LOCK(bufev);
- if (lowmark)
- *lowmark = bufev->wm_write.low;
- if (highmark)
- *highmark = bufev->wm_write.high;
- BEV_UNLOCK(bufev);
- return 0;
- }
-
- if (events == EV_READ) {
- BEV_LOCK(bufev);
- if (lowmark)
- *lowmark = bufev->wm_read.low;
- if (highmark)
- *highmark = bufev->wm_read.high;
- BEV_UNLOCK(bufev);
- return 0;
- }
- return -1;
-}
-
-int
-bufferevent_flush(struct bufferevent *bufev,
- short iotype,
- enum bufferevent_flush_mode mode)
-{
- int r = -1;
- BEV_LOCK(bufev);
- if (bufev->be_ops->flush)
- r = bufev->be_ops->flush(bufev, iotype, mode);
- BEV_UNLOCK(bufev);
- return r;
-}
-
-void
-bufferevent_incref_and_lock_(struct bufferevent *bufev)
-{
- struct bufferevent_private *bufev_private =
- BEV_UPCAST(bufev);
- BEV_LOCK(bufev);
- ++bufev_private->refcnt;
-}
-
-#if 0
-static void
-bufferevent_transfer_lock_ownership_(struct bufferevent *donor,
- struct bufferevent *recipient)
-{
- struct bufferevent_private *d = BEV_UPCAST(donor);
- struct bufferevent_private *r = BEV_UPCAST(recipient);
- if (d->lock != r->lock)
- return;
- if (r->own_lock)
- return;
- if (d->own_lock) {
- d->own_lock = 0;
- r->own_lock = 1;
- }
-}
-#endif
-
-int
-bufferevent_decref_and_unlock_(struct bufferevent *bufev)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- int n_cbs = 0;
-#define MAX_CBS 16
- struct event_callback *cbs[MAX_CBS];
-
- EVUTIL_ASSERT(bufev_private->refcnt > 0);
-
- if (--bufev_private->refcnt) {
- BEV_UNLOCK(bufev);
- return 0;
- }
-
- if (bufev->be_ops->unlink)
- bufev->be_ops->unlink(bufev);
-
- /* Okay, we're out of references. Let's finalize this once all the
- * callbacks are done running. */
- cbs[0] = &bufev->ev_read.ev_evcallback;
- cbs[1] = &bufev->ev_write.ev_evcallback;
- cbs[2] = &bufev_private->deferred;
- n_cbs = 3;
- if (bufev_private->rate_limiting) {
- struct event *e = &bufev_private->rate_limiting->refill_bucket_event;
- if (event_initialized(e))
- cbs[n_cbs++] = &e->ev_evcallback;
- }
- n_cbs += evbuffer_get_callbacks_(bufev->input, cbs+n_cbs, MAX_CBS-n_cbs);
- n_cbs += evbuffer_get_callbacks_(bufev->output, cbs+n_cbs, MAX_CBS-n_cbs);
-
- event_callback_finalize_many_(bufev->ev_base, n_cbs, cbs,
- bufferevent_finalize_cb_);
-
-#undef MAX_CBS
- BEV_UNLOCK(bufev);
-
- return 1;
-}
-
-static void
-bufferevent_finalize_cb_(struct event_callback *evcb, void *arg_)
-{
- struct bufferevent *bufev = arg_;
- struct bufferevent *underlying;
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
-
- BEV_LOCK(bufev);
- underlying = bufferevent_get_underlying(bufev);
-
- /* Clean up the shared info */
- if (bufev->be_ops->destruct)
- bufev->be_ops->destruct(bufev);
-
- /* XXX what happens if refcnt for these buffers is > 1?
- * The buffers can share a lock with this bufferevent object,
- * but the lock might be destroyed below. */
- /* evbuffer will free the callbacks */
- evbuffer_free(bufev->input);
- evbuffer_free(bufev->output);
-
- if (bufev_private->rate_limiting) {
- if (bufev_private->rate_limiting->group)
- bufferevent_remove_from_rate_limit_group_internal_(bufev,0);
- mm_free(bufev_private->rate_limiting);
- bufev_private->rate_limiting = NULL;
- }
-
-
- BEV_UNLOCK(bufev);
-
- if (bufev_private->own_lock)
- EVTHREAD_FREE_LOCK(bufev_private->lock,
- EVTHREAD_LOCKTYPE_RECURSIVE);
-
- /* Free the actual allocated memory. */
- mm_free(((char*)bufev) - bufev->be_ops->mem_offset);
-
- /* Release the reference to underlying now that we no longer need the
- * reference to it. We wait this long mainly in case our lock is
- * shared with underlying.
- *
- * The 'destruct' function will also drop a reference to underlying
- * if BEV_OPT_CLOSE_ON_FREE is set.
- *
- * XXX Should we/can we just refcount evbuffer/bufferevent locks?
- * It would probably save us some headaches.
- */
- if (underlying)
- bufferevent_decref_(underlying);
-}
-
-int
-bufferevent_decref(struct bufferevent *bufev)
-{
- BEV_LOCK(bufev);
- return bufferevent_decref_and_unlock_(bufev);
-}
-
-void
-bufferevent_free(struct bufferevent *bufev)
-{
- BEV_LOCK(bufev);
- bufferevent_setcb(bufev, NULL, NULL, NULL, NULL);
- bufferevent_cancel_all_(bufev);
- bufferevent_decref_and_unlock_(bufev);
-}
-
-void
-bufferevent_incref(struct bufferevent *bufev)
-{
- struct bufferevent_private *bufev_private =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
-
- /* XXX: now that this function is public, we might want to
- * - return the count from this function
- * - create a new function to atomically grab the current refcount
- */
- BEV_LOCK(bufev);
- ++bufev_private->refcnt;
- BEV_UNLOCK(bufev);
-}
-
-int
-bufferevent_enable_locking_(struct bufferevent *bufev, void *lock)
-{
-#ifdef EVENT__DISABLE_THREAD_SUPPORT
- return -1;
-#else
- struct bufferevent *underlying;
-
- if (BEV_UPCAST(bufev)->lock)
- return -1;
- underlying = bufferevent_get_underlying(bufev);
-
- if (!lock && underlying && BEV_UPCAST(underlying)->lock) {
- lock = BEV_UPCAST(underlying)->lock;
- BEV_UPCAST(bufev)->lock = lock;
- BEV_UPCAST(bufev)->own_lock = 0;
- } else if (!lock) {
- EVTHREAD_ALLOC_LOCK(lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- if (!lock)
- return -1;
- BEV_UPCAST(bufev)->lock = lock;
- BEV_UPCAST(bufev)->own_lock = 1;
- } else {
- BEV_UPCAST(bufev)->lock = lock;
- BEV_UPCAST(bufev)->own_lock = 0;
- }
- evbuffer_enable_locking(bufev->input, lock);
- evbuffer_enable_locking(bufev->output, lock);
-
- if (underlying && !BEV_UPCAST(underlying)->lock)
- bufferevent_enable_locking_(underlying, lock);
-
- return 0;
-#endif
-}
-
-int
-bufferevent_setfd(struct bufferevent *bev, evutil_socket_t fd)
-{
- union bufferevent_ctrl_data d;
- int res = -1;
- d.fd = fd;
- BEV_LOCK(bev);
- if (bev->be_ops->ctrl)
- res = bev->be_ops->ctrl(bev, BEV_CTRL_SET_FD, &d);
- BEV_UNLOCK(bev);
- return res;
-}
-
-evutil_socket_t
-bufferevent_getfd(struct bufferevent *bev)
-{
- union bufferevent_ctrl_data d;
- int res = -1;
- d.fd = -1;
- BEV_LOCK(bev);
- if (bev->be_ops->ctrl)
- res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_FD, &d);
- BEV_UNLOCK(bev);
- return (res<0) ? -1 : d.fd;
-}
-
-enum bufferevent_options
-bufferevent_get_options_(struct bufferevent *bev)
-{
- struct bufferevent_private *bev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
- enum bufferevent_options options;
-
- BEV_LOCK(bev);
- options = bev_p->options;
- BEV_UNLOCK(bev);
- return options;
-}
-
-
-static void
-bufferevent_cancel_all_(struct bufferevent *bev)
-{
- union bufferevent_ctrl_data d;
- memset(&d, 0, sizeof(d));
- BEV_LOCK(bev);
- if (bev->be_ops->ctrl)
- bev->be_ops->ctrl(bev, BEV_CTRL_CANCEL_ALL, &d);
- BEV_UNLOCK(bev);
-}
-
-short
-bufferevent_get_enabled(struct bufferevent *bufev)
-{
- short r;
- BEV_LOCK(bufev);
- r = bufev->enabled;
- BEV_UNLOCK(bufev);
- return r;
-}
-
-struct bufferevent *
-bufferevent_get_underlying(struct bufferevent *bev)
-{
- union bufferevent_ctrl_data d;
- int res = -1;
- d.ptr = NULL;
- BEV_LOCK(bev);
- if (bev->be_ops->ctrl)
- res = bev->be_ops->ctrl(bev, BEV_CTRL_GET_UNDERLYING, &d);
- BEV_UNLOCK(bev);
- return (res<0) ? NULL : d.ptr;
-}
-
-static void
-bufferevent_generic_read_timeout_cb(evutil_socket_t fd, short event, void *ctx)
-{
- struct bufferevent *bev = ctx;
- bufferevent_incref_and_lock_(bev);
- bufferevent_disable(bev, EV_READ);
- bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
- bufferevent_decref_and_unlock_(bev);
-}
-static void
-bufferevent_generic_write_timeout_cb(evutil_socket_t fd, short event, void *ctx)
-{
- struct bufferevent *bev = ctx;
- bufferevent_incref_and_lock_(bev);
- bufferevent_disable(bev, EV_WRITE);
- bufferevent_run_eventcb_(bev, BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
- bufferevent_decref_and_unlock_(bev);
-}
-
-void
-bufferevent_init_generic_timeout_cbs_(struct bufferevent *bev)
-{
- event_assign(&bev->ev_read, bev->ev_base, -1, EV_FINALIZE,
- bufferevent_generic_read_timeout_cb, bev);
- event_assign(&bev->ev_write, bev->ev_base, -1, EV_FINALIZE,
- bufferevent_generic_write_timeout_cb, bev);
-}
-
-int
-bufferevent_generic_adj_timeouts_(struct bufferevent *bev)
-{
- const short enabled = bev->enabled;
- struct bufferevent_private *bev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
- int r1=0, r2=0;
- if ((enabled & EV_READ) && !bev_p->read_suspended &&
- evutil_timerisset(&bev->timeout_read))
- r1 = event_add(&bev->ev_read, &bev->timeout_read);
- else
- r1 = event_del(&bev->ev_read);
-
- if ((enabled & EV_WRITE) && !bev_p->write_suspended &&
- evutil_timerisset(&bev->timeout_write) &&
- evbuffer_get_length(bev->output))
- r2 = event_add(&bev->ev_write, &bev->timeout_write);
- else
- r2 = event_del(&bev->ev_write);
- if (r1 < 0 || r2 < 0)
- return -1;
- return 0;
-}
-
-int
-bufferevent_generic_adj_existing_timeouts_(struct bufferevent *bev)
-{
- int r = 0;
- if (event_pending(&bev->ev_read, EV_READ, NULL)) {
- if (evutil_timerisset(&bev->timeout_read)) {
- if (bufferevent_add_event_(&bev->ev_read, &bev->timeout_read) < 0)
- r = -1;
- } else {
- event_remove_timer(&bev->ev_read);
- }
- }
- if (event_pending(&bev->ev_write, EV_WRITE, NULL)) {
- if (evutil_timerisset(&bev->timeout_write)) {
- if (bufferevent_add_event_(&bev->ev_write, &bev->timeout_write) < 0)
- r = -1;
- } else {
- event_remove_timer(&bev->ev_write);
- }
- }
- return r;
-}
-
-int
-bufferevent_add_event_(struct event *ev, const struct timeval *tv)
-{
- if (!evutil_timerisset(tv))
- return event_add(ev, NULL);
- else
- return event_add(ev, tv);
-}
-
-/* For use by user programs only; internally, we should be calling
- either bufferevent_incref_and_lock_(), or BEV_LOCK. */
-void
-bufferevent_lock(struct bufferevent *bev)
-{
- bufferevent_incref_and_lock_(bev);
-}
-
-void
-bufferevent_unlock(struct bufferevent *bev)
-{
- bufferevent_decref_and_unlock_(bev);
-}
diff --git a/libs/libevent/src/bufferevent_async.c b/libs/libevent/src/bufferevent_async.c
deleted file mode 100644
index 6395e57a9f..0000000000
--- a/libs/libevent/src/bufferevent_async.c
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-
-#include <sys/queue.h>
-
-#include "event2/util.h"
-#include "event2/bufferevent.h"
-#include "event2/buffer.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/event.h"
-#include "event2/util.h"
-#include "event-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "bufferevent-internal.h"
-#include "util-internal.h"
-#include "iocp-internal.h"
-
-#ifndef SO_UPDATE_CONNECT_CONTEXT
-/* Mingw is sometimes missing this */
-#define SO_UPDATE_CONNECT_CONTEXT 0x7010
-#endif
-
-/* prototypes */
-static int be_async_enable(struct bufferevent *, short);
-static int be_async_disable(struct bufferevent *, short);
-static void be_async_destruct(struct bufferevent *);
-static int be_async_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
-static int be_async_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
-
-struct bufferevent_async {
- struct bufferevent_private bev;
- struct event_overlapped connect_overlapped;
- struct event_overlapped read_overlapped;
- struct event_overlapped write_overlapped;
- size_t read_in_progress;
- size_t write_in_progress;
- unsigned ok : 1;
- unsigned read_added : 1;
- unsigned write_added : 1;
-};
-
-const struct bufferevent_ops bufferevent_ops_async = {
- "socket_async",
- evutil_offsetof(struct bufferevent_async, bev.bev),
- be_async_enable,
- be_async_disable,
- NULL, /* Unlink */
- be_async_destruct,
- bufferevent_generic_adj_timeouts_,
- be_async_flush,
- be_async_ctrl,
-};
-
-static inline struct bufferevent_async *
-upcast(struct bufferevent *bev)
-{
- struct bufferevent_async *bev_a;
- if (bev->be_ops != &bufferevent_ops_async)
- return NULL;
- bev_a = EVUTIL_UPCAST(bev, struct bufferevent_async, bev.bev);
- return bev_a;
-}
-
-static inline struct bufferevent_async *
-upcast_connect(struct event_overlapped *eo)
-{
- struct bufferevent_async *bev_a;
- bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, connect_overlapped);
- EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
- return bev_a;
-}
-
-static inline struct bufferevent_async *
-upcast_read(struct event_overlapped *eo)
-{
- struct bufferevent_async *bev_a;
- bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, read_overlapped);
- EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
- return bev_a;
-}
-
-static inline struct bufferevent_async *
-upcast_write(struct event_overlapped *eo)
-{
- struct bufferevent_async *bev_a;
- bev_a = EVUTIL_UPCAST(eo, struct bufferevent_async, write_overlapped);
- EVUTIL_ASSERT(BEV_IS_ASYNC(&bev_a->bev.bev));
- return bev_a;
-}
-
-static void
-bev_async_del_write(struct bufferevent_async *beva)
-{
- struct bufferevent *bev = &beva->bev.bev;
-
- if (beva->write_added) {
- beva->write_added = 0;
- event_base_del_virtual_(bev->ev_base);
- }
-}
-
-static void
-bev_async_del_read(struct bufferevent_async *beva)
-{
- struct bufferevent *bev = &beva->bev.bev;
-
- if (beva->read_added) {
- beva->read_added = 0;
- event_base_del_virtual_(bev->ev_base);
- }
-}
-
-static void
-bev_async_add_write(struct bufferevent_async *beva)
-{
- struct bufferevent *bev = &beva->bev.bev;
-
- if (!beva->write_added) {
- beva->write_added = 1;
- event_base_add_virtual_(bev->ev_base);
- }
-}
-
-static void
-bev_async_add_read(struct bufferevent_async *beva)
-{
- struct bufferevent *bev = &beva->bev.bev;
-
- if (!beva->read_added) {
- beva->read_added = 1;
- event_base_add_virtual_(bev->ev_base);
- }
-}
-
-static void
-bev_async_consider_writing(struct bufferevent_async *beva)
-{
- size_t at_most;
- int limit;
- struct bufferevent *bev = &beva->bev.bev;
-
- /* Don't write if there's a write in progress, or we do not
- * want to write, or when there's nothing left to write. */
- if (beva->write_in_progress || beva->bev.connecting)
- return;
- if (!beva->ok || !(bev->enabled&EV_WRITE) ||
- !evbuffer_get_length(bev->output)) {
- bev_async_del_write(beva);
- return;
- }
-
- at_most = evbuffer_get_length(bev->output);
-
- /* This is safe so long as bufferevent_get_write_max never returns
- * more than INT_MAX. That's true for now. XXXX */
- limit = (int)bufferevent_get_write_max_(&beva->bev);
- if (at_most >= (size_t)limit && limit >= 0)
- at_most = limit;
-
- if (beva->bev.write_suspended) {
- bev_async_del_write(beva);
- return;
- }
-
- /* XXXX doesn't respect low-water mark very well. */
- bufferevent_incref_(bev);
- if (evbuffer_launch_write_(bev->output, at_most,
- &beva->write_overlapped)) {
- bufferevent_decref_(bev);
- beva->ok = 0;
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
- } else {
- beva->write_in_progress = at_most;
- bufferevent_decrement_write_buckets_(&beva->bev, at_most);
- bev_async_add_write(beva);
- }
-}
-
-static void
-bev_async_consider_reading(struct bufferevent_async *beva)
-{
- size_t cur_size;
- size_t read_high;
- size_t at_most;
- int limit;
- struct bufferevent *bev = &beva->bev.bev;
-
- /* Don't read if there is a read in progress, or we do not
- * want to read. */
- if (beva->read_in_progress || beva->bev.connecting)
- return;
- if (!beva->ok || !(bev->enabled&EV_READ)) {
- bev_async_del_read(beva);
- return;
- }
-
- /* Don't read if we're full */
- cur_size = evbuffer_get_length(bev->input);
- read_high = bev->wm_read.high;
- if (read_high) {
- if (cur_size >= read_high) {
- bev_async_del_read(beva);
- return;
- }
- at_most = read_high - cur_size;
- } else {
- at_most = 16384; /* FIXME totally magic. */
- }
-
- /* XXXX This over-commits. */
- /* XXXX see also not above on cast on bufferevent_get_write_max_() */
- limit = (int)bufferevent_get_read_max_(&beva->bev);
- if (at_most >= (size_t)limit && limit >= 0)
- at_most = limit;
-
- if (beva->bev.read_suspended) {
- bev_async_del_read(beva);
- return;
- }
-
- bufferevent_incref_(bev);
- if (evbuffer_launch_read_(bev->input, at_most, &beva->read_overlapped)) {
- beva->ok = 0;
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
- bufferevent_decref_(bev);
- } else {
- beva->read_in_progress = at_most;
- bufferevent_decrement_read_buckets_(&beva->bev, at_most);
- bev_async_add_read(beva);
- }
-
- return;
-}
-
-static void
-be_async_outbuf_callback(struct evbuffer *buf,
- const struct evbuffer_cb_info *cbinfo,
- void *arg)
-{
- struct bufferevent *bev = arg;
- struct bufferevent_async *bev_async = upcast(bev);
-
- /* If we added data to the outbuf and were not writing before,
- * we may want to write now. */
-
- bufferevent_incref_and_lock_(bev);
-
- if (cbinfo->n_added)
- bev_async_consider_writing(bev_async);
-
- bufferevent_decref_and_unlock_(bev);
-}
-
-static void
-be_async_inbuf_callback(struct evbuffer *buf,
- const struct evbuffer_cb_info *cbinfo,
- void *arg)
-{
- struct bufferevent *bev = arg;
- struct bufferevent_async *bev_async = upcast(bev);
-
- /* If we drained data from the inbuf and were not reading before,
- * we may want to read now */
-
- bufferevent_incref_and_lock_(bev);
-
- if (cbinfo->n_deleted)
- bev_async_consider_reading(bev_async);
-
- bufferevent_decref_and_unlock_(bev);
-}
-
-static int
-be_async_enable(struct bufferevent *buf, short what)
-{
- struct bufferevent_async *bev_async = upcast(buf);
-
- if (!bev_async->ok)
- return -1;
-
- if (bev_async->bev.connecting) {
- /* Don't launch anything during connection attempts. */
- return 0;
- }
-
- if (what & EV_READ)
- BEV_RESET_GENERIC_READ_TIMEOUT(buf);
- if (what & EV_WRITE)
- BEV_RESET_GENERIC_WRITE_TIMEOUT(buf);
-
- /* If we newly enable reading or writing, and we aren't reading or
- writing already, consider launching a new read or write. */
-
- if (what & EV_READ)
- bev_async_consider_reading(bev_async);
- if (what & EV_WRITE)
- bev_async_consider_writing(bev_async);
- return 0;
-}
-
-static int
-be_async_disable(struct bufferevent *bev, short what)
-{
- struct bufferevent_async *bev_async = upcast(bev);
- /* XXXX If we disable reading or writing, we may want to consider
- * canceling any in-progress read or write operation, though it might
- * not work. */
-
- if (what & EV_READ) {
- BEV_DEL_GENERIC_READ_TIMEOUT(bev);
- bev_async_del_read(bev_async);
- }
- if (what & EV_WRITE) {
- BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
- bev_async_del_write(bev_async);
- }
-
- return 0;
-}
-
-static void
-be_async_destruct(struct bufferevent *bev)
-{
- struct bufferevent_async *bev_async = upcast(bev);
- struct bufferevent_private *bev_p = BEV_UPCAST(bev);
- evutil_socket_t fd;
-
- EVUTIL_ASSERT(!upcast(bev)->write_in_progress &&
- !upcast(bev)->read_in_progress);
-
- bev_async_del_read(bev_async);
- bev_async_del_write(bev_async);
-
- fd = evbuffer_overlapped_get_fd_(bev->input);
- if (fd != (evutil_socket_t)INVALID_SOCKET &&
- (bev_p->options & BEV_OPT_CLOSE_ON_FREE)) {
- evutil_closesocket(fd);
- evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
- }
-}
-
-/* GetQueuedCompletionStatus doesn't reliably yield WSA error codes, so
- * we use WSAGetOverlappedResult to translate. */
-static void
-bev_async_set_wsa_error(struct bufferevent *bev, struct event_overlapped *eo)
-{
- DWORD bytes, flags;
- evutil_socket_t fd;
-
- fd = evbuffer_overlapped_get_fd_(bev->input);
- WSAGetOverlappedResult(fd, &eo->overlapped, &bytes, FALSE, &flags);
-}
-
-static int
-be_async_flush(struct bufferevent *bev, short what,
- enum bufferevent_flush_mode mode)
-{
- return 0;
-}
-
-static void
-connect_complete(struct event_overlapped *eo, ev_uintptr_t key,
- ev_ssize_t nbytes, int ok)
-{
- struct bufferevent_async *bev_a = upcast_connect(eo);
- struct bufferevent *bev = &bev_a->bev.bev;
- evutil_socket_t sock;
-
- BEV_LOCK(bev);
-
- EVUTIL_ASSERT(bev_a->bev.connecting);
- bev_a->bev.connecting = 0;
- sock = evbuffer_overlapped_get_fd_(bev_a->bev.bev.input);
- /* XXXX Handle error? */
- setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
-
- if (ok)
- bufferevent_async_set_connected_(bev);
- else
- bev_async_set_wsa_error(bev, eo);
-
- bufferevent_run_eventcb_(bev,
- ok? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR, 0);
-
- event_base_del_virtual_(bev->ev_base);
-
- bufferevent_decref_and_unlock_(bev);
-}
-
-static void
-read_complete(struct event_overlapped *eo, ev_uintptr_t key,
- ev_ssize_t nbytes, int ok)
-{
- struct bufferevent_async *bev_a = upcast_read(eo);
- struct bufferevent *bev = &bev_a->bev.bev;
- short what = BEV_EVENT_READING;
- ev_ssize_t amount_unread;
- BEV_LOCK(bev);
- EVUTIL_ASSERT(bev_a->read_in_progress);
-
- amount_unread = bev_a->read_in_progress - nbytes;
- evbuffer_commit_read_(bev->input, nbytes);
- bev_a->read_in_progress = 0;
- if (amount_unread)
- bufferevent_decrement_read_buckets_(&bev_a->bev, -amount_unread);
-
- if (!ok)
- bev_async_set_wsa_error(bev, eo);
-
- if (bev_a->ok) {
- if (ok && nbytes) {
- BEV_RESET_GENERIC_READ_TIMEOUT(bev);
- bufferevent_trigger_nolock_(bev, EV_READ, 0);
- bev_async_consider_reading(bev_a);
- } else if (!ok) {
- what |= BEV_EVENT_ERROR;
- bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what, 0);
- } else if (!nbytes) {
- what |= BEV_EVENT_EOF;
- bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what, 0);
- }
- }
-
- bufferevent_decref_and_unlock_(bev);
-}
-
-static void
-write_complete(struct event_overlapped *eo, ev_uintptr_t key,
- ev_ssize_t nbytes, int ok)
-{
- struct bufferevent_async *bev_a = upcast_write(eo);
- struct bufferevent *bev = &bev_a->bev.bev;
- short what = BEV_EVENT_WRITING;
- ev_ssize_t amount_unwritten;
-
- BEV_LOCK(bev);
- EVUTIL_ASSERT(bev_a->write_in_progress);
-
- amount_unwritten = bev_a->write_in_progress - nbytes;
- evbuffer_commit_write_(bev->output, nbytes);
- bev_a->write_in_progress = 0;
-
- if (amount_unwritten)
- bufferevent_decrement_write_buckets_(&bev_a->bev,
- -amount_unwritten);
-
-
- if (!ok)
- bev_async_set_wsa_error(bev, eo);
-
- if (bev_a->ok) {
- if (ok && nbytes) {
- BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
- bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
- bev_async_consider_writing(bev_a);
- } else if (!ok) {
- what |= BEV_EVENT_ERROR;
- bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what, 0);
- } else if (!nbytes) {
- what |= BEV_EVENT_EOF;
- bev_a->ok = 0;
- bufferevent_run_eventcb_(bev, what, 0);
- }
- }
-
- bufferevent_decref_and_unlock_(bev);
-}
-
-struct bufferevent *
-bufferevent_async_new_(struct event_base *base,
- evutil_socket_t fd, int options)
-{
- struct bufferevent_async *bev_a;
- struct bufferevent *bev;
- struct event_iocp_port *iocp;
-
- options |= BEV_OPT_THREADSAFE;
-
- if (!(iocp = event_base_get_iocp_(base)))
- return NULL;
-
- if (fd >= 0 && event_iocp_port_associate_(iocp, fd, 1)<0) {
- int err = GetLastError();
- /* We may have alrady associated this fd with a port.
- * Let's hope it's this port, and that the error code
- * for doing this neer changes. */
- if (err != ERROR_INVALID_PARAMETER)
- return NULL;
- }
-
- if (!(bev_a = mm_calloc(1, sizeof(struct bufferevent_async))))
- return NULL;
-
- bev = &bev_a->bev.bev;
- if (!(bev->input = evbuffer_overlapped_new_(fd))) {
- mm_free(bev_a);
- return NULL;
- }
- if (!(bev->output = evbuffer_overlapped_new_(fd))) {
- evbuffer_free(bev->input);
- mm_free(bev_a);
- return NULL;
- }
-
- if (bufferevent_init_common_(&bev_a->bev, base, &bufferevent_ops_async,
- options)<0)
- goto err;
-
- evbuffer_add_cb(bev->input, be_async_inbuf_callback, bev);
- evbuffer_add_cb(bev->output, be_async_outbuf_callback, bev);
-
- event_overlapped_init_(&bev_a->connect_overlapped, connect_complete);
- event_overlapped_init_(&bev_a->read_overlapped, read_complete);
- event_overlapped_init_(&bev_a->write_overlapped, write_complete);
-
- bufferevent_init_generic_timeout_cbs_(bev);
-
- bev_a->ok = fd >= 0;
-
- return bev;
-err:
- bufferevent_free(&bev_a->bev.bev);
- return NULL;
-}
-
-void
-bufferevent_async_set_connected_(struct bufferevent *bev)
-{
- struct bufferevent_async *bev_async = upcast(bev);
- bev_async->ok = 1;
- bufferevent_init_generic_timeout_cbs_(bev);
- /* Now's a good time to consider reading/writing */
- be_async_enable(bev, bev->enabled);
-}
-
-int
-bufferevent_async_can_connect_(struct bufferevent *bev)
-{
- const struct win32_extension_fns *ext =
- event_get_win32_extension_fns_();
-
- if (BEV_IS_ASYNC(bev) &&
- event_base_get_iocp_(bev->ev_base) &&
- ext && ext->ConnectEx)
- return 1;
-
- return 0;
-}
-
-int
-bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd,
- const struct sockaddr *sa, int socklen)
-{
- BOOL rc;
- struct bufferevent_async *bev_async = upcast(bev);
- struct sockaddr_storage ss;
- const struct win32_extension_fns *ext =
- event_get_win32_extension_fns_();
-
- EVUTIL_ASSERT(ext && ext->ConnectEx && fd >= 0 && sa != NULL);
-
- /* ConnectEx() requires that the socket be bound to an address
- * with bind() before using, otherwise it will fail. We attempt
- * to issue a bind() here, taking into account that the error
- * code is set to WSAEINVAL when the socket is already bound. */
- memset(&ss, 0, sizeof(ss));
- if (sa->sa_family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = INADDR_ANY;
- } else if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_addr = in6addr_any;
- } else {
- /* Well, the user will have to bind() */
- return -1;
- }
- if (bind(fd, (struct sockaddr *)&ss, sizeof(ss)) < 0 &&
- WSAGetLastError() != WSAEINVAL)
- return -1;
-
- event_base_add_virtual_(bev->ev_base);
- bufferevent_incref_(bev);
- rc = ext->ConnectEx(fd, sa, socklen, NULL, 0, NULL,
- &bev_async->connect_overlapped.overlapped);
- if (rc || WSAGetLastError() == ERROR_IO_PENDING)
- return 0;
-
- event_base_del_virtual_(bev->ev_base);
- bufferevent_decref_(bev);
-
- return -1;
-}
-
-static int
-be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
- union bufferevent_ctrl_data *data)
-{
- switch (op) {
- case BEV_CTRL_GET_FD:
- data->fd = evbuffer_overlapped_get_fd_(bev->input);
- return 0;
- case BEV_CTRL_SET_FD: {
- struct event_iocp_port *iocp;
-
- if (data->fd == evbuffer_overlapped_get_fd_(bev->input))
- return 0;
- if (!(iocp = event_base_get_iocp_(bev->ev_base)))
- return -1;
- if (event_iocp_port_associate_(iocp, data->fd, 1) < 0)
- return -1;
- evbuffer_overlapped_set_fd_(bev->input, data->fd);
- evbuffer_overlapped_set_fd_(bev->output, data->fd);
- return 0;
- }
- case BEV_CTRL_CANCEL_ALL: {
- struct bufferevent_async *bev_a = upcast(bev);
- evutil_socket_t fd = evbuffer_overlapped_get_fd_(bev->input);
- if (fd != (evutil_socket_t)INVALID_SOCKET &&
- (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) {
- closesocket(fd);
- evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
- }
- bev_a->ok = 0;
- return 0;
- }
- case BEV_CTRL_GET_UNDERLYING:
- default:
- return -1;
- }
-}
-
-
diff --git a/libs/libevent/src/bufferevent_filter.c b/libs/libevent/src/bufferevent_filter.c
deleted file mode 100644
index 6c3ffc4f2d..0000000000
--- a/libs/libevent/src/bufferevent_filter.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#include "event2/event-config.h"
-
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-#include "event2/util.h"
-#include "event2/bufferevent.h"
-#include "event2/buffer.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/event.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "bufferevent-internal.h"
-#include "util-internal.h"
-
-/* prototypes */
-static int be_filter_enable(struct bufferevent *, short);
-static int be_filter_disable(struct bufferevent *, short);
-static void be_filter_unlink(struct bufferevent *);
-static void be_filter_destruct(struct bufferevent *);
-
-static void be_filter_readcb(struct bufferevent *, void *);
-static void be_filter_writecb(struct bufferevent *, void *);
-static void be_filter_eventcb(struct bufferevent *, short, void *);
-static int be_filter_flush(struct bufferevent *bufev,
- short iotype, enum bufferevent_flush_mode mode);
-static int be_filter_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
-
-static void bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
- const struct evbuffer_cb_info *info, void *arg);
-
-struct bufferevent_filtered {
- struct bufferevent_private bev;
-
- /** The bufferevent that we read/write filtered data from/to. */
- struct bufferevent *underlying;
- /** A callback on our outbuf to notice when somebody adds data */
- struct evbuffer_cb_entry *outbuf_cb;
- /** True iff we have received an EOF callback from the underlying
- * bufferevent. */
- unsigned got_eof;
-
- /** Function to free context when we're done. */
- void (*free_context)(void *);
- /** Input filter */
- bufferevent_filter_cb process_in;
- /** Output filter */
- bufferevent_filter_cb process_out;
- /** User-supplied argument to the filters. */
- void *context;
-};
-
-const struct bufferevent_ops bufferevent_ops_filter = {
- "filter",
- evutil_offsetof(struct bufferevent_filtered, bev.bev),
- be_filter_enable,
- be_filter_disable,
- be_filter_unlink,
- be_filter_destruct,
- bufferevent_generic_adj_timeouts_,
- be_filter_flush,
- be_filter_ctrl,
-};
-
-/* Given a bufferevent that's really the bev filter of a bufferevent_filtered,
- * return that bufferevent_filtered. Returns NULL otherwise.*/
-static inline struct bufferevent_filtered *
-upcast(struct bufferevent *bev)
-{
- struct bufferevent_filtered *bev_f;
- if (bev->be_ops != &bufferevent_ops_filter)
- return NULL;
- bev_f = (void*)( ((char*)bev) -
- evutil_offsetof(struct bufferevent_filtered, bev.bev));
- EVUTIL_ASSERT(bev_f->bev.bev.be_ops == &bufferevent_ops_filter);
- return bev_f;
-}
-
-#define downcast(bev_f) (&(bev_f)->bev.bev)
-
-/** Return 1 iff bevf's underlying bufferevent's output buffer is at or
- * over its high watermark such that we should not write to it in a given
- * flush mode. */
-static int
-be_underlying_writebuf_full(struct bufferevent_filtered *bevf,
- enum bufferevent_flush_mode state)
-{
- struct bufferevent *u = bevf->underlying;
- return state == BEV_NORMAL &&
- u->wm_write.high &&
- evbuffer_get_length(u->output) >= u->wm_write.high;
-}
-
-/** Return 1 if our input buffer is at or over its high watermark such that we
- * should not write to it in a given flush mode. */
-static int
-be_readbuf_full(struct bufferevent_filtered *bevf,
- enum bufferevent_flush_mode state)
-{
- struct bufferevent *bufev = downcast(bevf);
- return state == BEV_NORMAL &&
- bufev->wm_read.high &&
- evbuffer_get_length(bufev->input) >= bufev->wm_read.high;
-}
-
-
-/* Filter to use when we're created with a NULL filter. */
-static enum bufferevent_filter_result
-be_null_filter(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t lim,
- enum bufferevent_flush_mode state, void *ctx)
-{
- (void)state;
- if (evbuffer_remove_buffer(src, dst, lim) == 0)
- return BEV_OK;
- else
- return BEV_ERROR;
-}
-
-struct bufferevent *
-bufferevent_filter_new(struct bufferevent *underlying,
- bufferevent_filter_cb input_filter,
- bufferevent_filter_cb output_filter,
- int options,
- void (*free_context)(void *),
- void *ctx)
-{
- struct bufferevent_filtered *bufev_f;
- int tmp_options = options & ~BEV_OPT_THREADSAFE;
-
- if (!underlying)
- return NULL;
-
- if (!input_filter)
- input_filter = be_null_filter;
- if (!output_filter)
- output_filter = be_null_filter;
-
- bufev_f = mm_calloc(1, sizeof(struct bufferevent_filtered));
- if (!bufev_f)
- return NULL;
-
- if (bufferevent_init_common_(&bufev_f->bev, underlying->ev_base,
- &bufferevent_ops_filter, tmp_options) < 0) {
- mm_free(bufev_f);
- return NULL;
- }
- if (options & BEV_OPT_THREADSAFE) {
- bufferevent_enable_locking_(downcast(bufev_f), NULL);
- }
-
- bufev_f->underlying = underlying;
-
- bufev_f->process_in = input_filter;
- bufev_f->process_out = output_filter;
- bufev_f->free_context = free_context;
- bufev_f->context = ctx;
-
- bufferevent_setcb(bufev_f->underlying,
- be_filter_readcb, be_filter_writecb, be_filter_eventcb, bufev_f);
-
- bufev_f->outbuf_cb = evbuffer_add_cb(downcast(bufev_f)->output,
- bufferevent_filtered_outbuf_cb, bufev_f);
-
- bufferevent_init_generic_timeout_cbs_(downcast(bufev_f));
- bufferevent_incref_(underlying);
-
- bufferevent_enable(underlying, EV_READ|EV_WRITE);
- bufferevent_suspend_read_(underlying, BEV_SUSPEND_FILT_READ);
-
- return downcast(bufev_f);
-}
-
-static void
-be_filter_unlink(struct bufferevent *bev)
-{
- struct bufferevent_filtered *bevf = upcast(bev);
- EVUTIL_ASSERT(bevf);
-
- if (bevf->bev.options & BEV_OPT_CLOSE_ON_FREE) {
- /* Yes, there is also a decref in bufferevent_decref_.
- * That decref corresponds to the incref when we set
- * underlying for the first time. This decref is an
- * extra one to remove the last reference.
- */
- if (BEV_UPCAST(bevf->underlying)->refcnt < 2) {
- event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
- "bufferevent with too few references");
- } else {
- bufferevent_free(bevf->underlying);
- }
- } else {
- if (bevf->underlying) {
- if (bevf->underlying->errorcb == be_filter_eventcb)
- bufferevent_setcb(bevf->underlying,
- NULL, NULL, NULL, NULL);
- bufferevent_unsuspend_read_(bevf->underlying,
- BEV_SUSPEND_FILT_READ);
- }
- }
-}
-
-static void
-be_filter_destruct(struct bufferevent *bev)
-{
- struct bufferevent_filtered *bevf = upcast(bev);
- EVUTIL_ASSERT(bevf);
- if (bevf->free_context)
- bevf->free_context(bevf->context);
-}
-
-static int
-be_filter_enable(struct bufferevent *bev, short event)
-{
- struct bufferevent_filtered *bevf = upcast(bev);
- if (event & EV_WRITE)
- BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
-
- if (event & EV_READ) {
- BEV_RESET_GENERIC_READ_TIMEOUT(bev);
- bufferevent_unsuspend_read_(bevf->underlying,
- BEV_SUSPEND_FILT_READ);
- }
- return 0;
-}
-
-static int
-be_filter_disable(struct bufferevent *bev, short event)
-{
- struct bufferevent_filtered *bevf = upcast(bev);
- if (event & EV_WRITE)
- BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
- if (event & EV_READ) {
- BEV_DEL_GENERIC_READ_TIMEOUT(bev);
- bufferevent_suspend_read_(bevf->underlying,
- BEV_SUSPEND_FILT_READ);
- }
- return 0;
-}
-
-static enum bufferevent_filter_result
-be_filter_process_input(struct bufferevent_filtered *bevf,
- enum bufferevent_flush_mode state,
- int *processed_out)
-{
- enum bufferevent_filter_result res;
- struct bufferevent *bev = downcast(bevf);
-
- if (state == BEV_NORMAL) {
- /* If we're in 'normal' mode, don't urge data on the filter
- * unless we're reading data and under our high-water mark.*/
- if (!(bev->enabled & EV_READ) ||
- be_readbuf_full(bevf, state))
- return BEV_OK;
- }
-
- do {
- ev_ssize_t limit = -1;
- if (state == BEV_NORMAL && bev->wm_read.high)
- limit = bev->wm_read.high -
- evbuffer_get_length(bev->input);
-
- res = bevf->process_in(bevf->underlying->input,
- bev->input, limit, state, bevf->context);
-
- if (res == BEV_OK)
- *processed_out = 1;
- } while (res == BEV_OK &&
- (bev->enabled & EV_READ) &&
- evbuffer_get_length(bevf->underlying->input) &&
- !be_readbuf_full(bevf, state));
-
- if (*processed_out)
- BEV_RESET_GENERIC_READ_TIMEOUT(bev);
-
- return res;
-}
-
-
-static enum bufferevent_filter_result
-be_filter_process_output(struct bufferevent_filtered *bevf,
- enum bufferevent_flush_mode state,
- int *processed_out)
-{
- /* Requires references and lock: might call writecb */
- enum bufferevent_filter_result res = BEV_OK;
- struct bufferevent *bufev = downcast(bevf);
- int again = 0;
-
- if (state == BEV_NORMAL) {
- /* If we're in 'normal' mode, don't urge data on the
- * filter unless we're writing data, and the underlying
- * bufferevent is accepting data, and we have data to
- * give the filter. If we're in 'flush' or 'finish',
- * call the filter no matter what. */
- if (!(bufev->enabled & EV_WRITE) ||
- be_underlying_writebuf_full(bevf, state) ||
- !evbuffer_get_length(bufev->output))
- return BEV_OK;
- }
-
- /* disable the callback that calls this function
- when the user adds to the output buffer. */
- evbuffer_cb_set_flags(bufev->output, bevf->outbuf_cb, 0);
-
- do {
- int processed = 0;
- again = 0;
-
- do {
- ev_ssize_t limit = -1;
- if (state == BEV_NORMAL &&
- bevf->underlying->wm_write.high)
- limit = bevf->underlying->wm_write.high -
- evbuffer_get_length(bevf->underlying->output);
-
- res = bevf->process_out(downcast(bevf)->output,
- bevf->underlying->output,
- limit,
- state,
- bevf->context);
-
- if (res == BEV_OK)
- processed = *processed_out = 1;
- } while (/* Stop if the filter wasn't successful...*/
- res == BEV_OK &&
- /* Or if we aren't writing any more. */
- (bufev->enabled & EV_WRITE) &&
- /* Of if we have nothing more to write and we are
- * not flushing. */
- evbuffer_get_length(bufev->output) &&
- /* Or if we have filled the underlying output buffer. */
- !be_underlying_writebuf_full(bevf,state));
-
- if (processed) {
- /* call the write callback.*/
- bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
-
- if (res == BEV_OK &&
- (bufev->enabled & EV_WRITE) &&
- evbuffer_get_length(bufev->output) &&
- !be_underlying_writebuf_full(bevf, state)) {
- again = 1;
- }
- }
- } while (again);
-
- /* reenable the outbuf_cb */
- evbuffer_cb_set_flags(bufev->output,bevf->outbuf_cb,
- EVBUFFER_CB_ENABLED);
-
- if (*processed_out)
- BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
-
- return res;
-}
-
-/* Called when the size of our outbuf changes. */
-static void
-bufferevent_filtered_outbuf_cb(struct evbuffer *buf,
- const struct evbuffer_cb_info *cbinfo, void *arg)
-{
- struct bufferevent_filtered *bevf = arg;
- struct bufferevent *bev = downcast(bevf);
-
- if (cbinfo->n_added) {
- int processed_any = 0;
- /* Somebody added more data to the output buffer. Try to
- * process it, if we should. */
- bufferevent_incref_and_lock_(bev);
- be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
- bufferevent_decref_and_unlock_(bev);
- }
-}
-
-/* Called when the underlying socket has read. */
-static void
-be_filter_readcb(struct bufferevent *underlying, void *me_)
-{
- struct bufferevent_filtered *bevf = me_;
- enum bufferevent_filter_result res;
- enum bufferevent_flush_mode state;
- struct bufferevent *bufev = downcast(bevf);
- struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
- int processed_any = 0;
-
- BEV_LOCK(bufev);
-
- // It's possible our refcount is 0 at this point if another thread free'd our filterevent
- EVUTIL_ASSERT(bufev_private->refcnt >= 0);
-
- // If our refcount is > 0
- if (bufev_private->refcnt > 0) {
-
- if (bevf->got_eof)
- state = BEV_FINISHED;
- else
- state = BEV_NORMAL;
-
- /* XXXX use return value */
- res = be_filter_process_input(bevf, state, &processed_any);
- (void)res;
-
- /* XXX This should be in process_input, not here. There are
- * other places that can call process-input, and they should
- * force readcb calls as needed. */
- if (processed_any)
- bufferevent_trigger_nolock_(bufev, EV_READ, 0);
- }
-
- BEV_UNLOCK(bufev);
-}
-
-/* Called when the underlying socket has drained enough that we can write to
- it. */
-static void
-be_filter_writecb(struct bufferevent *underlying, void *me_)
-{
- struct bufferevent_filtered *bevf = me_;
- struct bufferevent *bev = downcast(bevf);
- struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
- int processed_any = 0;
-
- BEV_LOCK(bev);
-
- // It's possible our refcount is 0 at this point if another thread free'd our filterevent
- EVUTIL_ASSERT(bufev_private->refcnt >= 0);
-
- // If our refcount is > 0
- if (bufev_private->refcnt > 0) {
- be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
- }
-
- BEV_UNLOCK(bev);
-}
-
-/* Called when the underlying socket has given us an error */
-static void
-be_filter_eventcb(struct bufferevent *underlying, short what, void *me_)
-{
- struct bufferevent_filtered *bevf = me_;
- struct bufferevent *bev = downcast(bevf);
- struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
-
- BEV_LOCK(bev);
-
- // It's possible our refcount is 0 at this point if another thread free'd our filterevent
- EVUTIL_ASSERT(bufev_private->refcnt >= 0);
-
- // If our refcount is > 0
- if (bufev_private->refcnt > 0) {
-
- /* All we can really to is tell our own eventcb. */
- bufferevent_run_eventcb_(bev, what, 0);
- }
-
- BEV_UNLOCK(bev);
-}
-
-static int
-be_filter_flush(struct bufferevent *bufev,
- short iotype, enum bufferevent_flush_mode mode)
-{
- struct bufferevent_filtered *bevf = upcast(bufev);
- int processed_any = 0;
- EVUTIL_ASSERT(bevf);
-
- bufferevent_incref_and_lock_(bufev);
-
- if (iotype & EV_READ) {
- be_filter_process_input(bevf, mode, &processed_any);
- }
- if (iotype & EV_WRITE) {
- be_filter_process_output(bevf, mode, &processed_any);
- }
- /* XXX check the return value? */
- /* XXX does this want to recursively call lower-level flushes? */
- bufferevent_flush(bevf->underlying, iotype, mode);
-
- bufferevent_decref_and_unlock_(bufev);
-
- return processed_any;
-}
-
-static int
-be_filter_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
- union bufferevent_ctrl_data *data)
-{
- struct bufferevent_filtered *bevf;
- switch (op) {
- case BEV_CTRL_GET_UNDERLYING:
- bevf = upcast(bev);
- data->ptr = bevf->underlying;
- return 0;
- case BEV_CTRL_SET_FD:
- bevf = upcast(bev);
-
- if (bevf->underlying &&
- bevf->underlying->be_ops &&
- bevf->underlying->be_ops->ctrl) {
- return (bevf->underlying->be_ops->ctrl)(bevf->underlying, op, data);
- }
-
- case BEV_CTRL_GET_FD:
- case BEV_CTRL_CANCEL_ALL:
- default:
- return -1;
- }
-
- return -1;
-}
diff --git a/libs/libevent/src/bufferevent_openssl.c b/libs/libevent/src/bufferevent_openssl.c
deleted file mode 100644
index 37478b6a83..0000000000
--- a/libs/libevent/src/bufferevent_openssl.c
+++ /dev/null
@@ -1,1484 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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.
- */
-
-// Get rid of OSX 10.7 and greater deprecation warnings.
-#if defined(__APPLE__) && defined(__clang__)
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-#include "event2/bufferevent.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/bufferevent_ssl.h"
-#include "event2/buffer.h"
-#include "event2/event.h"
-
-#include "mm-internal.h"
-#include "bufferevent-internal.h"
-#include "log-internal.h"
-
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-
-/*
- * Define an OpenSSL bio that targets a bufferevent.
- */
-
-/* --------------------
- A BIO is an OpenSSL abstraction that handles reading and writing data. The
- library will happily speak SSL over anything that implements a BIO
- interface.
-
- Here we define a BIO implementation that directs its output to a
- bufferevent. We'll want to use this only when none of OpenSSL's built-in
- IO mechanisms work for us.
- -------------------- */
-
-/* every BIO type needs its own integer type value. */
-#define BIO_TYPE_LIBEVENT 57
-/* ???? Arguably, we should set BIO_TYPE_FILTER or BIO_TYPE_SOURCE_SINK on
- * this. */
-
-#if 0
-static void
-print_err(int val)
-{
- int err;
- printf("Error was %d\n", val);
-
- while ((err = ERR_get_error())) {
- const char *msg = (const char*)ERR_reason_error_string(err);
- const char *lib = (const char*)ERR_lib_error_string(err);
- const char *func = (const char*)ERR_func_error_string(err);
-
- printf("%s in %s %s\n", msg, lib, func);
- }
-}
-#else
-#define print_err(v) ((void)0)
-#endif
-
-/* Called to initialize a new BIO */
-static int
-bio_bufferevent_new(BIO *b)
-{
- b->init = 0;
- b->num = -1;
- b->ptr = NULL; /* We'll be putting the bufferevent in this field.*/
- b->flags = 0;
- return 1;
-}
-
-/* Called to uninitialize the BIO. */
-static int
-bio_bufferevent_free(BIO *b)
-{
- if (!b)
- return 0;
- if (b->shutdown) {
- if (b->init && b->ptr)
- bufferevent_free(b->ptr);
- b->init = 0;
- b->flags = 0;
- b->ptr = NULL;
- }
- return 1;
-}
-
-/* Called to extract data from the BIO. */
-static int
-bio_bufferevent_read(BIO *b, char *out, int outlen)
-{
- int r = 0;
- struct evbuffer *input;
-
- BIO_clear_retry_flags(b);
-
- if (!out)
- return 0;
- if (!b->ptr)
- return -1;
-
- input = bufferevent_get_input(b->ptr);
- if (evbuffer_get_length(input) == 0) {
- /* If there's no data to read, say so. */
- BIO_set_retry_read(b);
- return -1;
- } else {
- r = evbuffer_remove(input, out, outlen);
- }
-
- return r;
-}
-
-/* Called to write data info the BIO */
-static int
-bio_bufferevent_write(BIO *b, const char *in, int inlen)
-{
- struct bufferevent *bufev = b->ptr;
- struct evbuffer *output;
- size_t outlen;
-
- BIO_clear_retry_flags(b);
-
- if (!b->ptr)
- return -1;
-
- output = bufferevent_get_output(bufev);
- outlen = evbuffer_get_length(output);
-
- /* Copy only as much data onto the output buffer as can fit under the
- * high-water mark. */
- if (bufev->wm_write.high && bufev->wm_write.high <= (outlen+inlen)) {
- if (bufev->wm_write.high <= outlen) {
- /* If no data can fit, we'll need to retry later. */
- BIO_set_retry_write(b);
- return -1;
- }
- inlen = bufev->wm_write.high - outlen;
- }
-
- EVUTIL_ASSERT(inlen > 0);
- evbuffer_add(output, in, inlen);
- return inlen;
-}
-
-/* Called to handle various requests */
-static long
-bio_bufferevent_ctrl(BIO *b, int cmd, long num, void *ptr)
-{
- struct bufferevent *bufev = b->ptr;
- long ret = 1;
-
- switch (cmd) {
- case BIO_CTRL_GET_CLOSE:
- ret = b->shutdown;
- break;
- case BIO_CTRL_SET_CLOSE:
- b->shutdown = (int)num;
- break;
- case BIO_CTRL_PENDING:
- ret = evbuffer_get_length(bufferevent_get_input(bufev)) != 0;
- break;
- case BIO_CTRL_WPENDING:
- ret = evbuffer_get_length(bufferevent_get_output(bufev)) != 0;
- break;
- /* XXXX These two are given a special-case treatment because
- * of cargo-cultism. I should come up with a better reason. */
- case BIO_CTRL_DUP:
- case BIO_CTRL_FLUSH:
- ret = 1;
- break;
- default:
- ret = 0;
- break;
- }
- return ret;
-}
-
-/* Called to write a string to the BIO */
-static int
-bio_bufferevent_puts(BIO *b, const char *s)
-{
- return bio_bufferevent_write(b, s, strlen(s));
-}
-
-/* Method table for the bufferevent BIO */
-static BIO_METHOD methods_bufferevent = {
- BIO_TYPE_LIBEVENT, "bufferevent",
- bio_bufferevent_write,
- bio_bufferevent_read,
- bio_bufferevent_puts,
- NULL /* bio_bufferevent_gets */,
- bio_bufferevent_ctrl,
- bio_bufferevent_new,
- bio_bufferevent_free,
- NULL /* callback_ctrl */,
-};
-
-/* Return the method table for the bufferevents BIO */
-static BIO_METHOD *
-BIO_s_bufferevent(void)
-{
- return &methods_bufferevent;
-}
-
-/* Create a new BIO to wrap communication around a bufferevent. If close_flag
- * is true, the bufferevent will be freed when the BIO is closed. */
-static BIO *
-BIO_new_bufferevent(struct bufferevent *bufferevent, int close_flag)
-{
- BIO *result;
- if (!bufferevent)
- return NULL;
- if (!(result = BIO_new(BIO_s_bufferevent())))
- return NULL;
- result->init = 1;
- result->ptr = bufferevent;
- result->shutdown = close_flag ? 1 : 0;
- return result;
-}
-
-/* --------------------
- Now, here's the OpenSSL-based implementation of bufferevent.
-
- The implementation comes in two flavors: one that connects its SSL object
- to an underlying bufferevent using a BIO_bufferevent, and one that has the
- SSL object connect to a socket directly. The latter should generally be
- faster, except on Windows, where your best bet is using a
- bufferevent_async.
-
- (OpenSSL supports many other BIO types, too. But we can't use any unless
- we have a good way to get notified when they become readable/writable.)
- -------------------- */
-
-struct bio_data_counts {
- unsigned long n_written;
- unsigned long n_read;
-};
-
-struct bufferevent_openssl {
- /* Shared fields with common bufferevent implementation code.
- If we were set up with an underlying bufferevent, we use the
- events here as timers only. If we have an SSL, then we use
- the events as socket events.
- */
- struct bufferevent_private bev;
- /* An underlying bufferevent that we're directing our output to.
- If it's NULL, then we're connected to an fd, not an evbuffer. */
- struct bufferevent *underlying;
- /* The SSL object doing our encryption. */
- SSL *ssl;
-
- /* A callback that's invoked when data arrives on our outbuf so we
- know to write data to the SSL. */
- struct evbuffer_cb_entry *outbuf_cb;
-
- /* A count of how much data the bios have read/written total. Used
- for rate-limiting. */
- struct bio_data_counts counts;
-
- /* If this value is greater than 0, then the last SSL_write blocked,
- * and we need to try it again with this many bytes. */
- ev_ssize_t last_write;
-
-#define NUM_ERRORS 3
- ev_uint32_t errors[NUM_ERRORS];
-
- /* When we next get available space, we should say "read" instead of
- "write". This can happen if there's a renegotiation during a read
- operation. */
- unsigned read_blocked_on_write : 1;
- /* When we next get data, we should say "write" instead of "read". */
- unsigned write_blocked_on_read : 1;
- /* Treat TCP close before SSL close on SSL >= v3 as clean EOF. */
- unsigned allow_dirty_shutdown : 1;
- /* XXX */
- unsigned n_errors : 2;
-
- /* Are we currently connecting, accepting, or doing IO? */
- unsigned state : 2;
-};
-
-static int be_openssl_enable(struct bufferevent *, short);
-static int be_openssl_disable(struct bufferevent *, short);
-static void be_openssl_unlink(struct bufferevent *);
-static void be_openssl_destruct(struct bufferevent *);
-static int be_openssl_adj_timeouts(struct bufferevent *);
-static int be_openssl_flush(struct bufferevent *bufev,
- short iotype, enum bufferevent_flush_mode mode);
-static int be_openssl_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
-
-const struct bufferevent_ops bufferevent_ops_openssl = {
- "ssl",
- evutil_offsetof(struct bufferevent_openssl, bev.bev),
- be_openssl_enable,
- be_openssl_disable,
- be_openssl_unlink,
- be_openssl_destruct,
- be_openssl_adj_timeouts,
- be_openssl_flush,
- be_openssl_ctrl,
-};
-
-/* Given a bufferevent, return a pointer to the bufferevent_openssl that
- * contains it, if any. */
-static inline struct bufferevent_openssl *
-upcast(struct bufferevent *bev)
-{
- struct bufferevent_openssl *bev_o;
- if (bev->be_ops != &bufferevent_ops_openssl)
- return NULL;
- bev_o = (void*)( ((char*)bev) -
- evutil_offsetof(struct bufferevent_openssl, bev.bev));
- EVUTIL_ASSERT(bev_o->bev.bev.be_ops == &bufferevent_ops_openssl);
- return bev_o;
-}
-
-static inline void
-put_error(struct bufferevent_openssl *bev_ssl, unsigned long err)
-{
- if (bev_ssl->n_errors == NUM_ERRORS)
- return;
- /* The error type according to openssl is "unsigned long", but
- openssl never uses more than 32 bits of it. It _can't_ use more
- than 32 bits of it, since it needs to report errors on systems
- where long is only 32 bits.
- */
- bev_ssl->errors[bev_ssl->n_errors++] = (ev_uint32_t) err;
-}
-
-/* Have the base communications channel (either the underlying bufferevent or
- * ev_read and ev_write) start reading. Take the read-blocked-on-write flag
- * into account. */
-static int
-start_reading(struct bufferevent_openssl *bev_ssl)
-{
- if (bev_ssl->underlying) {
- bufferevent_unsuspend_read_(bev_ssl->underlying,
- BEV_SUSPEND_FILT_READ);
- return 0;
- } else {
- struct bufferevent *bev = &bev_ssl->bev.bev;
- int r;
- r = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
- if (r == 0 && bev_ssl->read_blocked_on_write)
- r = bufferevent_add_event_(&bev->ev_write,
- &bev->timeout_write);
- return r;
- }
-}
-
-/* Have the base communications channel (either the underlying bufferevent or
- * ev_read and ev_write) start writing. Take the write-blocked-on-read flag
- * into account. */
-static int
-start_writing(struct bufferevent_openssl *bev_ssl)
-{
- int r = 0;
- if (bev_ssl->underlying) {
- ;
- } else {
- struct bufferevent *bev = &bev_ssl->bev.bev;
- r = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
- if (!r && bev_ssl->write_blocked_on_read)
- r = bufferevent_add_event_(&bev->ev_read,
- &bev->timeout_read);
- }
- return r;
-}
-
-static void
-stop_reading(struct bufferevent_openssl *bev_ssl)
-{
- if (bev_ssl->write_blocked_on_read)
- return;
- if (bev_ssl->underlying) {
- bufferevent_suspend_read_(bev_ssl->underlying,
- BEV_SUSPEND_FILT_READ);
- } else {
- struct bufferevent *bev = &bev_ssl->bev.bev;
- event_del(&bev->ev_read);
- }
-}
-
-static void
-stop_writing(struct bufferevent_openssl *bev_ssl)
-{
- if (bev_ssl->read_blocked_on_write)
- return;
- if (bev_ssl->underlying) {
- ;
- } else {
- struct bufferevent *bev = &bev_ssl->bev.bev;
- event_del(&bev->ev_write);
- }
-}
-
-static int
-set_rbow(struct bufferevent_openssl *bev_ssl)
-{
- if (!bev_ssl->underlying)
- stop_reading(bev_ssl);
- bev_ssl->read_blocked_on_write = 1;
- return start_writing(bev_ssl);
-}
-
-static int
-set_wbor(struct bufferevent_openssl *bev_ssl)
-{
- if (!bev_ssl->underlying)
- stop_writing(bev_ssl);
- bev_ssl->write_blocked_on_read = 1;
- return start_reading(bev_ssl);
-}
-
-static int
-clear_rbow(struct bufferevent_openssl *bev_ssl)
-{
- struct bufferevent *bev = &bev_ssl->bev.bev;
- int r = 0;
- bev_ssl->read_blocked_on_write = 0;
- if (!(bev->enabled & EV_WRITE))
- stop_writing(bev_ssl);
- if (bev->enabled & EV_READ)
- r = start_reading(bev_ssl);
- return r;
-}
-
-
-static int
-clear_wbor(struct bufferevent_openssl *bev_ssl)
-{
- struct bufferevent *bev = &bev_ssl->bev.bev;
- int r = 0;
- bev_ssl->write_blocked_on_read = 0;
- if (!(bev->enabled & EV_READ))
- stop_reading(bev_ssl);
- if (bev->enabled & EV_WRITE)
- r = start_writing(bev_ssl);
- return r;
-}
-
-static void
-conn_closed(struct bufferevent_openssl *bev_ssl, int when, int errcode, int ret)
-{
- int event = BEV_EVENT_ERROR;
- int dirty_shutdown = 0;
- unsigned long err;
-
- switch (errcode) {
- case SSL_ERROR_ZERO_RETURN:
- /* Possibly a clean shutdown. */
- if (SSL_get_shutdown(bev_ssl->ssl) & SSL_RECEIVED_SHUTDOWN)
- event = BEV_EVENT_EOF;
- else
- dirty_shutdown = 1;
- break;
- case SSL_ERROR_SYSCALL:
- /* IO error; possibly a dirty shutdown. */
- if (ret == 0 && ERR_peek_error() == 0)
- dirty_shutdown = 1;
- break;
- case SSL_ERROR_SSL:
- /* Protocol error. */
- break;
- case SSL_ERROR_WANT_X509_LOOKUP:
- /* XXXX handle this. */
- break;
- case SSL_ERROR_NONE:
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_CONNECT:
- case SSL_ERROR_WANT_ACCEPT:
- default:
- /* should be impossible; treat as normal error. */
- event_warnx("BUG: Unexpected OpenSSL error code %d", errcode);
- break;
- }
-
- while ((err = ERR_get_error())) {
- put_error(bev_ssl, err);
- }
-
- if (dirty_shutdown && bev_ssl->allow_dirty_shutdown)
- event = BEV_EVENT_EOF;
-
- stop_reading(bev_ssl);
- stop_writing(bev_ssl);
-
- /* when is BEV_EVENT_{READING|WRITING} */
- event = when | event;
- bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
-}
-
-static void
-init_bio_counts(struct bufferevent_openssl *bev_ssl)
-{
- bev_ssl->counts.n_written =
- BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
- bev_ssl->counts.n_read =
- BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
-}
-
-static inline void
-decrement_buckets(struct bufferevent_openssl *bev_ssl)
-{
- unsigned long num_w = BIO_number_written(SSL_get_wbio(bev_ssl->ssl));
- unsigned long num_r = BIO_number_read(SSL_get_rbio(bev_ssl->ssl));
- /* These next two subtractions can wrap around. That's okay. */
- unsigned long w = num_w - bev_ssl->counts.n_written;
- unsigned long r = num_r - bev_ssl->counts.n_read;
- if (w)
- bufferevent_decrement_write_buckets_(&bev_ssl->bev, w);
- if (r)
- bufferevent_decrement_read_buckets_(&bev_ssl->bev, r);
- bev_ssl->counts.n_written = num_w;
- bev_ssl->counts.n_read = num_r;
-}
-
-#define OP_MADE_PROGRESS 1
-#define OP_BLOCKED 2
-#define OP_ERR 4
-
-/* Return a bitmask of OP_MADE_PROGRESS (if we read anything); OP_BLOCKED (if
- we're now blocked); and OP_ERR (if an error occurred). */
-static int
-do_read(struct bufferevent_openssl *bev_ssl, int n_to_read) {
- /* Requires lock */
- struct bufferevent *bev = &bev_ssl->bev.bev;
- struct evbuffer *input = bev->input;
- int r, n, i, n_used = 0, atmost;
- struct evbuffer_iovec space[2];
- int result = 0;
-
- if (bev_ssl->bev.read_suspended)
- return 0;
-
- atmost = bufferevent_get_read_max_(&bev_ssl->bev);
- if (n_to_read > atmost)
- n_to_read = atmost;
-
- n = evbuffer_reserve_space(input, n_to_read, space, 2);
- if (n < 0)
- return OP_ERR;
-
- for (i=0; i<n; ++i) {
- if (bev_ssl->bev.read_suspended)
- break;
- r = SSL_read(bev_ssl->ssl, space[i].iov_base, space[i].iov_len);
- if (r>0) {
- result |= OP_MADE_PROGRESS;
- if (bev_ssl->read_blocked_on_write)
- if (clear_rbow(bev_ssl) < 0)
- return OP_ERR | result;
- ++n_used;
- space[i].iov_len = r;
- decrement_buckets(bev_ssl);
- } else {
- int err = SSL_get_error(bev_ssl->ssl, r);
- print_err(err);
- switch (err) {
- case SSL_ERROR_WANT_READ:
- /* Can't read until underlying has more data. */
- if (bev_ssl->read_blocked_on_write)
- if (clear_rbow(bev_ssl) < 0)
- return OP_ERR | result;
- break;
- case SSL_ERROR_WANT_WRITE:
- /* This read operation requires a write, and the
- * underlying is full */
- if (!bev_ssl->read_blocked_on_write)
- if (set_rbow(bev_ssl) < 0)
- return OP_ERR | result;
- break;
- default:
- conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
- break;
- }
- result |= OP_BLOCKED;
- break; /* out of the loop */
- }
- }
-
- if (n_used) {
- evbuffer_commit_space(input, space, n_used);
- if (bev_ssl->underlying)
- BEV_RESET_GENERIC_READ_TIMEOUT(bev);
- }
-
- return result;
-}
-
-/* Return a bitmask of OP_MADE_PROGRESS (if we wrote anything); OP_BLOCKED (if
- we're now blocked); and OP_ERR (if an error occurred). */
-static int
-do_write(struct bufferevent_openssl *bev_ssl, int atmost)
-{
- int i, r, n, n_written = 0;
- struct bufferevent *bev = &bev_ssl->bev.bev;
- struct evbuffer *output = bev->output;
- struct evbuffer_iovec space[8];
- int result = 0;
-
- if (bev_ssl->last_write > 0)
- atmost = bev_ssl->last_write;
- else
- atmost = bufferevent_get_write_max_(&bev_ssl->bev);
-
- n = evbuffer_peek(output, atmost, NULL, space, 8);
- if (n < 0)
- return OP_ERR | result;
-
- if (n > 8)
- n = 8;
- for (i=0; i < n; ++i) {
- if (bev_ssl->bev.write_suspended)
- break;
-
- /* SSL_write will (reasonably) return 0 if we tell it to
- send 0 data. Skip this case so we don't interpret the
- result as an error */
- if (space[i].iov_len == 0)
- continue;
-
- r = SSL_write(bev_ssl->ssl, space[i].iov_base,
- space[i].iov_len);
- if (r > 0) {
- result |= OP_MADE_PROGRESS;
- if (bev_ssl->write_blocked_on_read)
- if (clear_wbor(bev_ssl) < 0)
- return OP_ERR | result;
- n_written += r;
- bev_ssl->last_write = -1;
- decrement_buckets(bev_ssl);
- } else {
- int err = SSL_get_error(bev_ssl->ssl, r);
- print_err(err);
- switch (err) {
- case SSL_ERROR_WANT_WRITE:
- /* Can't read until underlying has more data. */
- if (bev_ssl->write_blocked_on_read)
- if (clear_wbor(bev_ssl) < 0)
- return OP_ERR | result;
- bev_ssl->last_write = space[i].iov_len;
- break;
- case SSL_ERROR_WANT_READ:
- /* This read operation requires a write, and the
- * underlying is full */
- if (!bev_ssl->write_blocked_on_read)
- if (set_wbor(bev_ssl) < 0)
- return OP_ERR | result;
- bev_ssl->last_write = space[i].iov_len;
- break;
- default:
- conn_closed(bev_ssl, BEV_EVENT_WRITING, err, r);
- bev_ssl->last_write = -1;
- break;
- }
- result |= OP_BLOCKED;
- break;
- }
- }
- if (n_written) {
- evbuffer_drain(output, n_written);
- if (bev_ssl->underlying)
- BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
-
- bufferevent_trigger_nolock_(bev, EV_WRITE, 0);
- }
- return result;
-}
-
-#define WRITE_FRAME 15000
-
-#define READ_DEFAULT 4096
-
-/* Try to figure out how many bytes to read; return 0 if we shouldn't be
- * reading. */
-static int
-bytes_to_read(struct bufferevent_openssl *bev)
-{
- struct evbuffer *input = bev->bev.bev.input;
- struct event_watermark *wm = &bev->bev.bev.wm_read;
- int result = READ_DEFAULT;
- ev_ssize_t limit;
- /* XXX 99% of this is generic code that nearly all bufferevents will
- * want. */
-
- if (bev->write_blocked_on_read) {
- return 0;
- }
-
- if (! (bev->bev.bev.enabled & EV_READ)) {
- return 0;
- }
-
- if (bev->bev.read_suspended) {
- return 0;
- }
-
- if (wm->high) {
- if (evbuffer_get_length(input) >= wm->high) {
- return 0;
- }
-
- result = wm->high - evbuffer_get_length(input);
- } else {
- result = READ_DEFAULT;
- }
-
- /* Respect the rate limit */
- limit = bufferevent_get_read_max_(&bev->bev);
- if (result > limit) {
- result = limit;
- }
-
- return result;
-}
-
-
-/* Things look readable. If write is blocked on read, write till it isn't.
- * Read from the underlying buffer until we block or we hit our high-water
- * mark.
- */
-static void
-consider_reading(struct bufferevent_openssl *bev_ssl)
-{
- int r;
- int n_to_read;
- int all_result_flags = 0;
-
- while (bev_ssl->write_blocked_on_read) {
- r = do_write(bev_ssl, WRITE_FRAME);
- if (r & (OP_BLOCKED|OP_ERR))
- break;
- }
- if (bev_ssl->write_blocked_on_read)
- return;
-
- n_to_read = bytes_to_read(bev_ssl);
-
- while (n_to_read) {
- r = do_read(bev_ssl, n_to_read);
- all_result_flags |= r;
-
- if (r & (OP_BLOCKED|OP_ERR))
- break;
-
- if (bev_ssl->bev.read_suspended)
- break;
-
- /* Read all pending data. This won't hit the network
- * again, and will (most importantly) put us in a state
- * where we don't need to read anything else until the
- * socket is readable again. It'll potentially make us
- * overrun our read high-watermark (somewhat
- * regrettable). The damage to the rate-limit has
- * already been done, since OpenSSL went and read a
- * whole SSL record anyway. */
- n_to_read = SSL_pending(bev_ssl->ssl);
-
- /* XXX This if statement is actually a bad bug, added to avoid
- * XXX a worse bug.
- *
- * The bad bug: It can potentially cause resource unfairness
- * by reading too much data from the underlying bufferevent;
- * it can potentially cause read looping if the underlying
- * bufferevent is a bufferevent_pair and deferred callbacks
- * aren't used.
- *
- * The worse bug: If we didn't do this, then we would
- * potentially not read any more from bev_ssl->underlying
- * until more data arrived there, which could lead to us
- * waiting forever.
- */
- if (!n_to_read && bev_ssl->underlying)
- n_to_read = bytes_to_read(bev_ssl);
- }
-
- if (all_result_flags & OP_MADE_PROGRESS) {
- struct bufferevent *bev = &bev_ssl->bev.bev;
-
- bufferevent_trigger_nolock_(bev, EV_READ, 0);
- }
-
- if (!bev_ssl->underlying) {
- /* Should be redundant, but let's avoid busy-looping */
- if (bev_ssl->bev.read_suspended ||
- !(bev_ssl->bev.bev.enabled & EV_READ)) {
- event_del(&bev_ssl->bev.bev.ev_read);
- }
- }
-}
-
-static void
-consider_writing(struct bufferevent_openssl *bev_ssl)
-{
- int r;
- struct evbuffer *output = bev_ssl->bev.bev.output;
- struct evbuffer *target = NULL;
- struct event_watermark *wm = NULL;
-
- while (bev_ssl->read_blocked_on_write) {
- r = do_read(bev_ssl, 1024); /* XXXX 1024 is a hack */
- if (r & OP_MADE_PROGRESS) {
- struct bufferevent *bev = &bev_ssl->bev.bev;
-
- bufferevent_trigger_nolock_(bev, EV_READ, 0);
- }
- if (r & (OP_ERR|OP_BLOCKED))
- break;
- }
- if (bev_ssl->read_blocked_on_write)
- return;
- if (bev_ssl->underlying) {
- target = bev_ssl->underlying->output;
- wm = &bev_ssl->underlying->wm_write;
- }
- while ((bev_ssl->bev.bev.enabled & EV_WRITE) &&
- (! bev_ssl->bev.write_suspended) &&
- evbuffer_get_length(output) &&
- (!target || (! wm->high || evbuffer_get_length(target) < wm->high))) {
- int n_to_write;
- if (wm && wm->high)
- n_to_write = wm->high - evbuffer_get_length(target);
- else
- n_to_write = WRITE_FRAME;
- r = do_write(bev_ssl, n_to_write);
- if (r & (OP_BLOCKED|OP_ERR))
- break;
- }
-
- if (!bev_ssl->underlying) {
- if (evbuffer_get_length(output) == 0) {
- event_del(&bev_ssl->bev.bev.ev_write);
- } else if (bev_ssl->bev.write_suspended ||
- !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
- /* Should be redundant, but let's avoid busy-looping */
- event_del(&bev_ssl->bev.bev.ev_write);
- }
- }
-}
-
-static void
-be_openssl_readcb(struct bufferevent *bev_base, void *ctx)
-{
- struct bufferevent_openssl *bev_ssl = ctx;
- consider_reading(bev_ssl);
-}
-
-static void
-be_openssl_writecb(struct bufferevent *bev_base, void *ctx)
-{
- struct bufferevent_openssl *bev_ssl = ctx;
- consider_writing(bev_ssl);
-}
-
-static void
-be_openssl_eventcb(struct bufferevent *bev_base, short what, void *ctx)
-{
- struct bufferevent_openssl *bev_ssl = ctx;
- int event = 0;
-
- if (what & BEV_EVENT_EOF) {
- if (bev_ssl->allow_dirty_shutdown)
- event = BEV_EVENT_EOF;
- else
- event = BEV_EVENT_ERROR;
- } else if (what & BEV_EVENT_TIMEOUT) {
- /* We sure didn't set this. Propagate it to the user. */
- event = what;
- } else if (what & BEV_EVENT_ERROR) {
- /* An error occurred on the connection. Propagate it to the user. */
- event = what;
- } else if (what & BEV_EVENT_CONNECTED) {
- /* Ignore it. We're saying SSL_connect() already, which will
- eat it. */
- }
- if (event)
- bufferevent_run_eventcb_(&bev_ssl->bev.bev, event, 0);
-}
-
-static void
-be_openssl_readeventcb(evutil_socket_t fd, short what, void *ptr)
-{
- struct bufferevent_openssl *bev_ssl = ptr;
- bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
- if (what == EV_TIMEOUT) {
- bufferevent_run_eventcb_(&bev_ssl->bev.bev,
- BEV_EVENT_TIMEOUT|BEV_EVENT_READING, 0);
- } else {
- consider_reading(bev_ssl);
- }
- bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
-}
-
-static void
-be_openssl_writeeventcb(evutil_socket_t fd, short what, void *ptr)
-{
- struct bufferevent_openssl *bev_ssl = ptr;
- bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
- if (what == EV_TIMEOUT) {
- bufferevent_run_eventcb_(&bev_ssl->bev.bev,
- BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING, 0);
- } else {
- consider_writing(bev_ssl);
- }
- bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
-}
-
-static int
-be_openssl_auto_fd(struct bufferevent_openssl *bev_ssl, int fd)
-{
- if (!bev_ssl->underlying) {
- struct bufferevent *bev = &bev_ssl->bev.bev;
- if (event_initialized(&bev->ev_read) && fd < 0) {
- fd = event_get_fd(&bev->ev_read);
- }
- }
- return fd;
-}
-
-static int
-set_open_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
-{
- if (bev_ssl->underlying) {
- bufferevent_setcb(bev_ssl->underlying,
- be_openssl_readcb, be_openssl_writecb, be_openssl_eventcb,
- bev_ssl);
- return 0;
- } else {
- struct bufferevent *bev = &bev_ssl->bev.bev;
- int rpending=0, wpending=0, r1=0, r2=0;
-
- if (event_initialized(&bev->ev_read)) {
- rpending = event_pending(&bev->ev_read, EV_READ, NULL);
- wpending = event_pending(&bev->ev_write, EV_WRITE, NULL);
-
- event_del(&bev->ev_read);
- event_del(&bev->ev_write);
- }
-
- event_assign(&bev->ev_read, bev->ev_base, fd,
- EV_READ|EV_PERSIST|EV_FINALIZE,
- be_openssl_readeventcb, bev_ssl);
- event_assign(&bev->ev_write, bev->ev_base, fd,
- EV_WRITE|EV_PERSIST|EV_FINALIZE,
- be_openssl_writeeventcb, bev_ssl);
-
- if (rpending)
- r1 = bufferevent_add_event_(&bev->ev_read, &bev->timeout_read);
- if (wpending)
- r2 = bufferevent_add_event_(&bev->ev_write, &bev->timeout_write);
-
- return (r1<0 || r2<0) ? -1 : 0;
- }
-}
-static int
-set_open_callbacks_auto(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
-{
- fd = be_openssl_auto_fd(bev_ssl, fd);
- return set_open_callbacks(bev_ssl, fd);
-}
-
-static int
-do_handshake(struct bufferevent_openssl *bev_ssl)
-{
- int r;
-
- switch (bev_ssl->state) {
- default:
- case BUFFEREVENT_SSL_OPEN:
- EVUTIL_ASSERT(0);
- return -1;
- case BUFFEREVENT_SSL_CONNECTING:
- case BUFFEREVENT_SSL_ACCEPTING:
- r = SSL_do_handshake(bev_ssl->ssl);
- break;
- }
- decrement_buckets(bev_ssl);
-
- if (r==1) {
- int fd = event_get_fd(&bev_ssl->bev.bev.ev_read);
- /* We're done! */
- bev_ssl->state = BUFFEREVENT_SSL_OPEN;
- set_open_callbacks(bev_ssl, fd); /* XXXX handle failure */
- /* Call do_read and do_write as needed */
- bufferevent_enable(&bev_ssl->bev.bev, bev_ssl->bev.bev.enabled);
- bufferevent_run_eventcb_(&bev_ssl->bev.bev,
- BEV_EVENT_CONNECTED, 0);
- return 1;
- } else {
- int err = SSL_get_error(bev_ssl->ssl, r);
- print_err(err);
- switch (err) {
- case SSL_ERROR_WANT_WRITE:
- if (!bev_ssl->underlying) {
- stop_reading(bev_ssl);
- return start_writing(bev_ssl);
- }
- return 0;
- case SSL_ERROR_WANT_READ:
- if (!bev_ssl->underlying) {
- stop_writing(bev_ssl);
- return start_reading(bev_ssl);
- }
- return 0;
- default:
- conn_closed(bev_ssl, BEV_EVENT_READING, err, r);
- return -1;
- }
- }
-}
-
-static void
-be_openssl_handshakecb(struct bufferevent *bev_base, void *ctx)
-{
- struct bufferevent_openssl *bev_ssl = ctx;
- do_handshake(bev_ssl);/* XXX handle failure */
-}
-
-static void
-be_openssl_handshakeeventcb(evutil_socket_t fd, short what, void *ptr)
-{
- struct bufferevent_openssl *bev_ssl = ptr;
-
- bufferevent_incref_and_lock_(&bev_ssl->bev.bev);
- if (what & EV_TIMEOUT) {
- bufferevent_run_eventcb_(&bev_ssl->bev.bev, BEV_EVENT_TIMEOUT, 0);
- } else
- do_handshake(bev_ssl);/* XXX handle failure */
- bufferevent_decref_and_unlock_(&bev_ssl->bev.bev);
-}
-
-static int
-set_handshake_callbacks(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
-{
- if (bev_ssl->underlying) {
- bufferevent_setcb(bev_ssl->underlying,
- be_openssl_handshakecb, be_openssl_handshakecb,
- be_openssl_eventcb,
- bev_ssl);
- return do_handshake(bev_ssl);
- } else {
- struct bufferevent *bev = &bev_ssl->bev.bev;
-
- if (event_initialized(&bev->ev_read)) {
- event_del(&bev->ev_read);
- event_del(&bev->ev_write);
- }
-
- event_assign(&bev->ev_read, bev->ev_base, fd,
- EV_READ|EV_PERSIST|EV_FINALIZE,
- be_openssl_handshakeeventcb, bev_ssl);
- event_assign(&bev->ev_write, bev->ev_base, fd,
- EV_WRITE|EV_PERSIST|EV_FINALIZE,
- be_openssl_handshakeeventcb, bev_ssl);
- if (fd >= 0)
- bufferevent_enable(bev, bev->enabled);
- return 0;
- }
-}
-
-static int
-set_handshake_callbacks_auto(struct bufferevent_openssl *bev_ssl, evutil_socket_t fd)
-{
- fd = be_openssl_auto_fd(bev_ssl, fd);
- return set_handshake_callbacks(bev_ssl, fd);
-}
-
-int
-bufferevent_ssl_renegotiate(struct bufferevent *bev)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
- if (!bev_ssl)
- return -1;
- if (SSL_renegotiate(bev_ssl->ssl) < 0)
- return -1;
- bev_ssl->state = BUFFEREVENT_SSL_CONNECTING;
- if (set_handshake_callbacks_auto(bev_ssl, -1) < 0)
- return -1;
- if (!bev_ssl->underlying)
- return do_handshake(bev_ssl);
- return 0;
-}
-
-static void
-be_openssl_outbuf_cb(struct evbuffer *buf,
- const struct evbuffer_cb_info *cbinfo, void *arg)
-{
- struct bufferevent_openssl *bev_ssl = arg;
- int r = 0;
- /* XXX need to hold a reference here. */
-
- if (cbinfo->n_added && bev_ssl->state == BUFFEREVENT_SSL_OPEN &&
- cbinfo->orig_size == 0) {
- r = bufferevent_add_event_(&bev_ssl->bev.bev.ev_write,
- &bev_ssl->bev.bev.timeout_write);
- }
- /* XXX Handle r < 0 */
- (void)r;
-}
-
-
-static int
-be_openssl_enable(struct bufferevent *bev, short events)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
- int r1 = 0, r2 = 0;
-
- if (events & EV_READ)
- r1 = start_reading(bev_ssl);
- if (events & EV_WRITE)
- r2 = start_writing(bev_ssl);
-
- if (bev_ssl->underlying) {
- if (events & EV_READ)
- BEV_RESET_GENERIC_READ_TIMEOUT(bev);
- if (events & EV_WRITE)
- BEV_RESET_GENERIC_WRITE_TIMEOUT(bev);
-
- if (events & EV_READ)
- consider_reading(bev_ssl);
- if (events & EV_WRITE)
- consider_writing(bev_ssl);
- }
- return (r1 < 0 || r2 < 0) ? -1 : 0;
-}
-
-static int
-be_openssl_disable(struct bufferevent *bev, short events)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
-
- if (events & EV_READ)
- stop_reading(bev_ssl);
- if (events & EV_WRITE)
- stop_writing(bev_ssl);
-
- if (bev_ssl->underlying) {
- if (events & EV_READ)
- BEV_DEL_GENERIC_READ_TIMEOUT(bev);
- if (events & EV_WRITE)
- BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
- }
- return 0;
-}
-
-static void
-be_openssl_unlink(struct bufferevent *bev)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
-
- if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
- if (bev_ssl->underlying) {
- if (BEV_UPCAST(bev_ssl->underlying)->refcnt < 2) {
- event_warnx("BEV_OPT_CLOSE_ON_FREE set on an "
- "bufferevent with too few references");
- } else {
- bufferevent_free(bev_ssl->underlying);
- /* We still have a reference to it, via our
- * BIO. So we don't drop this. */
- // bev_ssl->underlying = NULL;
- }
- }
- } else {
- if (bev_ssl->underlying) {
- if (bev_ssl->underlying->errorcb == be_openssl_eventcb)
- bufferevent_setcb(bev_ssl->underlying,
- NULL,NULL,NULL,NULL);
- bufferevent_unsuspend_read_(bev_ssl->underlying,
- BEV_SUSPEND_FILT_READ);
- }
- }
-}
-
-static void
-be_openssl_destruct(struct bufferevent *bev)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
-
- if (bev_ssl->bev.options & BEV_OPT_CLOSE_ON_FREE) {
- if (! bev_ssl->underlying) {
- evutil_socket_t fd = -1;
- BIO *bio = SSL_get_wbio(bev_ssl->ssl);
- if (bio)
- fd = BIO_get_fd(bio, NULL);
- if (fd >= 0)
- evutil_closesocket(fd);
- }
- SSL_free(bev_ssl->ssl);
- }
-}
-
-static int
-be_openssl_adj_timeouts(struct bufferevent *bev)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
-
- if (bev_ssl->underlying) {
- return bufferevent_generic_adj_timeouts_(bev);
- } else {
- return bufferevent_generic_adj_existing_timeouts_(bev);
- }
-}
-
-static int
-be_openssl_flush(struct bufferevent *bufev,
- short iotype, enum bufferevent_flush_mode mode)
-{
- /* XXXX Implement this. */
- return 0;
-}
-
-static int
-be_openssl_ctrl(struct bufferevent *bev,
- enum bufferevent_ctrl_op op, union bufferevent_ctrl_data *data)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bev);
- switch (op) {
- case BEV_CTRL_SET_FD:
- if (bev_ssl->underlying)
- return -1;
- {
- BIO *bio;
- bio = BIO_new_socket(data->fd, 0);
- SSL_set_bio(bev_ssl->ssl, bio, bio);
- }
- if (bev_ssl->state == BUFFEREVENT_SSL_OPEN && data->fd >= 0)
- return set_open_callbacks(bev_ssl, data->fd);
- else {
- return set_handshake_callbacks(bev_ssl, data->fd);
- }
- case BEV_CTRL_GET_FD:
- data->fd = event_get_fd(&bev->ev_read);
- return 0;
- case BEV_CTRL_GET_UNDERLYING:
- data->ptr = bev_ssl->underlying;
- return 0;
- case BEV_CTRL_CANCEL_ALL:
- default:
- return -1;
- }
-}
-
-SSL *
-bufferevent_openssl_get_ssl(struct bufferevent *bufev)
-{
- struct bufferevent_openssl *bev_ssl = upcast(bufev);
- if (!bev_ssl)
- return NULL;
- return bev_ssl->ssl;
-}
-
-static struct bufferevent *
-bufferevent_openssl_new_impl(struct event_base *base,
- struct bufferevent *underlying,
- evutil_socket_t fd,
- SSL *ssl,
- enum bufferevent_ssl_state state,
- int options)
-{
- struct bufferevent_openssl *bev_ssl = NULL;
- struct bufferevent_private *bev_p = NULL;
- int tmp_options = options & ~BEV_OPT_THREADSAFE;
-
- if (underlying != NULL && fd >= 0)
- return NULL; /* Only one can be set. */
-
- if (!(bev_ssl = mm_calloc(1, sizeof(struct bufferevent_openssl))))
- goto err;
-
- bev_p = &bev_ssl->bev;
-
- if (bufferevent_init_common_(bev_p, base,
- &bufferevent_ops_openssl, tmp_options) < 0)
- goto err;
-
- /* Don't explode if we decide to realloc a chunk we're writing from in
- * the output buffer. */
- SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
- bev_ssl->underlying = underlying;
- bev_ssl->ssl = ssl;
-
- bev_ssl->outbuf_cb = evbuffer_add_cb(bev_p->bev.output,
- be_openssl_outbuf_cb, bev_ssl);
-
- if (options & BEV_OPT_THREADSAFE)
- bufferevent_enable_locking_(&bev_ssl->bev.bev, NULL);
-
- if (underlying) {
- bufferevent_init_generic_timeout_cbs_(&bev_ssl->bev.bev);
- bufferevent_incref_(underlying);
- }
-
- bev_ssl->state = state;
- bev_ssl->last_write = -1;
-
- init_bio_counts(bev_ssl);
-
- switch (state) {
- case BUFFEREVENT_SSL_ACCEPTING:
- SSL_set_accept_state(bev_ssl->ssl);
- if (set_handshake_callbacks_auto(bev_ssl, fd) < 0)
- goto err;
- break;
- case BUFFEREVENT_SSL_CONNECTING:
- SSL_set_connect_state(bev_ssl->ssl);
- if (set_handshake_callbacks_auto(bev_ssl, fd) < 0)
- goto err;
- break;
- case BUFFEREVENT_SSL_OPEN:
- if (set_open_callbacks_auto(bev_ssl, fd) < 0)
- goto err;
- break;
- default:
- goto err;
- }
-
- if (underlying) {
- bufferevent_setwatermark(underlying, EV_READ, 0, 0);
- bufferevent_enable(underlying, EV_READ|EV_WRITE);
- if (state == BUFFEREVENT_SSL_OPEN)
- bufferevent_suspend_read_(underlying,
- BEV_SUSPEND_FILT_READ);
- }
-
- return &bev_ssl->bev.bev;
-err:
- if (bev_ssl)
- bufferevent_free(&bev_ssl->bev.bev);
- return NULL;
-}
-
-struct bufferevent *
-bufferevent_openssl_filter_new(struct event_base *base,
- struct bufferevent *underlying,
- SSL *ssl,
- enum bufferevent_ssl_state state,
- int options)
-{
- /* We don't tell the BIO to close the bufferevent; we do it ourselves
- * on be_openssl_destruct */
- int close_flag = 0; /* options & BEV_OPT_CLOSE_ON_FREE; */
- BIO *bio;
- if (!underlying)
- return NULL;
- if (!(bio = BIO_new_bufferevent(underlying, close_flag)))
- return NULL;
-
- SSL_set_bio(ssl, bio, bio);
-
- return bufferevent_openssl_new_impl(
- base, underlying, -1, ssl, state, options);
-}
-
-struct bufferevent *
-bufferevent_openssl_socket_new(struct event_base *base,
- evutil_socket_t fd,
- SSL *ssl,
- enum bufferevent_ssl_state state,
- int options)
-{
- /* Does the SSL already have an fd? */
- BIO *bio = SSL_get_wbio(ssl);
- long have_fd = -1;
-
- if (bio)
- have_fd = BIO_get_fd(bio, NULL);
-
- if (have_fd >= 0) {
- /* The SSL is already configured with an fd. */
- if (fd < 0) {
- /* We should learn the fd from the SSL. */
- fd = (evutil_socket_t) have_fd;
- } else if (have_fd == (long)fd) {
- /* We already know the fd from the SSL; do nothing */
- } else {
- /* We specified an fd different from that of the SSL.
- This is probably an error on our part. Fail. */
- return NULL;
- }
- (void) BIO_set_close(bio, 0);
- } else {
- /* The SSL isn't configured with a BIO with an fd. */
- if (fd >= 0) {
- /* ... and we have an fd we want to use. */
- bio = BIO_new_socket(fd, 0);
- SSL_set_bio(ssl, bio, bio);
- } else {
- /* Leave the fd unset. */
- }
- }
-
- return bufferevent_openssl_new_impl(
- base, NULL, fd, ssl, state, options);
-}
-
-int
-bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev)
-{
- int allow_dirty_shutdown = -1;
- struct bufferevent_openssl *bev_ssl;
- BEV_LOCK(bev);
- bev_ssl = upcast(bev);
- if (bev_ssl)
- allow_dirty_shutdown = bev_ssl->allow_dirty_shutdown;
- BEV_UNLOCK(bev);
- return allow_dirty_shutdown;
-}
-
-void
-bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
- int allow_dirty_shutdown)
-{
- struct bufferevent_openssl *bev_ssl;
- BEV_LOCK(bev);
- bev_ssl = upcast(bev);
- if (bev_ssl)
- bev_ssl->allow_dirty_shutdown = !!allow_dirty_shutdown;
- BEV_UNLOCK(bev);
-}
-
-unsigned long
-bufferevent_get_openssl_error(struct bufferevent *bev)
-{
- unsigned long err = 0;
- struct bufferevent_openssl *bev_ssl;
- BEV_LOCK(bev);
- bev_ssl = upcast(bev);
- if (bev_ssl && bev_ssl->n_errors) {
- err = bev_ssl->errors[--bev_ssl->n_errors];
- }
- BEV_UNLOCK(bev);
- return err;
-}
diff --git a/libs/libevent/src/bufferevent_pair.c b/libs/libevent/src/bufferevent_pair.c
deleted file mode 100644
index d80e5f81d6..0000000000
--- a/libs/libevent/src/bufferevent_pair.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-#include "event2/util.h"
-#include "event2/buffer.h"
-#include "event2/bufferevent.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/event.h"
-#include "defer-internal.h"
-#include "bufferevent-internal.h"
-#include "mm-internal.h"
-#include "util-internal.h"
-
-struct bufferevent_pair {
- struct bufferevent_private bev;
- struct bufferevent_pair *partner;
- /* For ->destruct() lock checking */
- struct bufferevent_pair *unlinked_partner;
-};
-
-
-/* Given a bufferevent that's really a bev part of a bufferevent_pair,
- * return that bufferevent_filtered. Returns NULL otherwise.*/
-static inline struct bufferevent_pair *
-upcast(struct bufferevent *bev)
-{
- struct bufferevent_pair *bev_p;
- if (bev->be_ops != &bufferevent_ops_pair)
- return NULL;
- bev_p = EVUTIL_UPCAST(bev, struct bufferevent_pair, bev.bev);
- EVUTIL_ASSERT(bev_p->bev.bev.be_ops == &bufferevent_ops_pair);
- return bev_p;
-}
-
-#define downcast(bev_pair) (&(bev_pair)->bev.bev)
-
-static inline void
-incref_and_lock(struct bufferevent *b)
-{
- struct bufferevent_pair *bevp;
- bufferevent_incref_and_lock_(b);
- bevp = upcast(b);
- if (bevp->partner)
- bufferevent_incref_and_lock_(downcast(bevp->partner));
-}
-
-static inline void
-decref_and_unlock(struct bufferevent *b)
-{
- struct bufferevent_pair *bevp = upcast(b);
- if (bevp->partner)
- bufferevent_decref_and_unlock_(downcast(bevp->partner));
- bufferevent_decref_and_unlock_(b);
-}
-
-/* XXX Handle close */
-
-static void be_pair_outbuf_cb(struct evbuffer *,
- const struct evbuffer_cb_info *, void *);
-
-static struct bufferevent_pair *
-bufferevent_pair_elt_new(struct event_base *base,
- int options)
-{
- struct bufferevent_pair *bufev;
- if (! (bufev = mm_calloc(1, sizeof(struct bufferevent_pair))))
- return NULL;
- if (bufferevent_init_common_(&bufev->bev, base, &bufferevent_ops_pair,
- options)) {
- mm_free(bufev);
- return NULL;
- }
- if (!evbuffer_add_cb(bufev->bev.bev.output, be_pair_outbuf_cb, bufev)) {
- bufferevent_free(downcast(bufev));
- return NULL;
- }
-
- bufferevent_init_generic_timeout_cbs_(&bufev->bev.bev);
-
- return bufev;
-}
-
-int
-bufferevent_pair_new(struct event_base *base, int options,
- struct bufferevent *pair[2])
-{
- struct bufferevent_pair *bufev1 = NULL, *bufev2 = NULL;
- int tmp_options;
-
- options |= BEV_OPT_DEFER_CALLBACKS;
- tmp_options = options & ~BEV_OPT_THREADSAFE;
-
- bufev1 = bufferevent_pair_elt_new(base, options);
- if (!bufev1)
- return -1;
- bufev2 = bufferevent_pair_elt_new(base, tmp_options);
- if (!bufev2) {
- bufferevent_free(downcast(bufev1));
- return -1;
- }
-
- if (options & BEV_OPT_THREADSAFE) {
- /*XXXX check return */
- bufferevent_enable_locking_(downcast(bufev2), bufev1->bev.lock);
- }
-
- bufev1->partner = bufev2;
- bufev2->partner = bufev1;
-
- evbuffer_freeze(downcast(bufev1)->input, 0);
- evbuffer_freeze(downcast(bufev1)->output, 1);
- evbuffer_freeze(downcast(bufev2)->input, 0);
- evbuffer_freeze(downcast(bufev2)->output, 1);
-
- pair[0] = downcast(bufev1);
- pair[1] = downcast(bufev2);
-
- return 0;
-}
-
-static void
-be_pair_transfer(struct bufferevent *src, struct bufferevent *dst,
- int ignore_wm)
-{
- size_t dst_size;
- size_t n;
-
- evbuffer_unfreeze(src->output, 1);
- evbuffer_unfreeze(dst->input, 0);
-
- if (dst->wm_read.high) {
- dst_size = evbuffer_get_length(dst->input);
- if (dst_size < dst->wm_read.high) {
- n = dst->wm_read.high - dst_size;
- evbuffer_remove_buffer(src->output, dst->input, n);
- } else {
- if (!ignore_wm)
- goto done;
- n = evbuffer_get_length(src->output);
- evbuffer_add_buffer(dst->input, src->output);
- }
- } else {
- n = evbuffer_get_length(src->output);
- evbuffer_add_buffer(dst->input, src->output);
- }
-
- if (n) {
- BEV_RESET_GENERIC_READ_TIMEOUT(dst);
-
- if (evbuffer_get_length(dst->output))
- BEV_RESET_GENERIC_WRITE_TIMEOUT(dst);
- else
- BEV_DEL_GENERIC_WRITE_TIMEOUT(dst);
- }
-
- bufferevent_trigger_nolock_(dst, EV_READ, 0);
- bufferevent_trigger_nolock_(src, EV_WRITE, 0);
-done:
- evbuffer_freeze(src->output, 1);
- evbuffer_freeze(dst->input, 0);
-}
-
-static inline int
-be_pair_wants_to_talk(struct bufferevent_pair *src,
- struct bufferevent_pair *dst)
-{
- return (downcast(src)->enabled & EV_WRITE) &&
- (downcast(dst)->enabled & EV_READ) &&
- !dst->bev.read_suspended &&
- evbuffer_get_length(downcast(src)->output);
-}
-
-static void
-be_pair_outbuf_cb(struct evbuffer *outbuf,
- const struct evbuffer_cb_info *info, void *arg)
-{
- struct bufferevent_pair *bev_pair = arg;
- struct bufferevent_pair *partner = bev_pair->partner;
-
- incref_and_lock(downcast(bev_pair));
-
- if (info->n_added > info->n_deleted && partner) {
- /* We got more data. If the other side's reading, then
- hand it over. */
- if (be_pair_wants_to_talk(bev_pair, partner)) {
- be_pair_transfer(downcast(bev_pair), downcast(partner), 0);
- }
- }
-
- decref_and_unlock(downcast(bev_pair));
-}
-
-static int
-be_pair_enable(struct bufferevent *bufev, short events)
-{
- struct bufferevent_pair *bev_p = upcast(bufev);
- struct bufferevent_pair *partner = bev_p->partner;
-
- incref_and_lock(bufev);
-
- if (events & EV_READ) {
- BEV_RESET_GENERIC_READ_TIMEOUT(bufev);
- }
- if ((events & EV_WRITE) && evbuffer_get_length(bufev->output))
- BEV_RESET_GENERIC_WRITE_TIMEOUT(bufev);
-
- /* We're starting to read! Does the other side have anything to write?*/
- if ((events & EV_READ) && partner &&
- be_pair_wants_to_talk(partner, bev_p)) {
- be_pair_transfer(downcast(partner), bufev, 0);
- }
- /* We're starting to write! Does the other side want to read? */
- if ((events & EV_WRITE) && partner &&
- be_pair_wants_to_talk(bev_p, partner)) {
- be_pair_transfer(bufev, downcast(partner), 0);
- }
- decref_and_unlock(bufev);
- return 0;
-}
-
-static int
-be_pair_disable(struct bufferevent *bev, short events)
-{
- if (events & EV_READ) {
- BEV_DEL_GENERIC_READ_TIMEOUT(bev);
- }
- if (events & EV_WRITE) {
- BEV_DEL_GENERIC_WRITE_TIMEOUT(bev);
- }
- return 0;
-}
-
-static void
-be_pair_unlink(struct bufferevent *bev)
-{
- struct bufferevent_pair *bev_p = upcast(bev);
-
- if (bev_p->partner) {
- bev_p->unlinked_partner = bev_p->partner;
- bev_p->partner->partner = NULL;
- bev_p->partner = NULL;
- }
-}
-
-/* Free *shared* lock in the latest be (since we share it between two of them). */
-static void
-be_pair_destruct(struct bufferevent *bev)
-{
- struct bufferevent_pair *bev_p = upcast(bev);
-
- /* Transfer ownership of the lock into partner, otherwise we will use
- * already free'd lock during freeing second bev, see next example:
- *
- * bev1->own_lock = 1
- * bev2->own_lock = 0
- * bev2->lock = bev1->lock
- *
- * bufferevent_free(bev1) # refcnt == 0 -> unlink
- * bufferevent_free(bev2) # refcnt == 0 -> unlink
- *
- * event_base_free() -> finilizers -> EVTHREAD_FREE_LOCK(bev1->lock)
- * -> BEV_LOCK(bev2->lock) <-- already freed
- *
- * Where bev1 == pair[0], bev2 == pair[1].
- */
- if (bev_p->unlinked_partner && bev_p->bev.own_lock) {
- bev_p->unlinked_partner->bev.own_lock = 1;
- bev_p->bev.own_lock = 0;
- }
- bev_p->unlinked_partner = NULL;
-}
-
-static int
-be_pair_flush(struct bufferevent *bev, short iotype,
- enum bufferevent_flush_mode mode)
-{
- struct bufferevent_pair *bev_p = upcast(bev);
- struct bufferevent *partner;
-
- if (!bev_p->partner)
- return -1;
-
- if (mode == BEV_NORMAL)
- return 0;
-
- incref_and_lock(bev);
-
- partner = downcast(bev_p->partner);
-
- if ((iotype & EV_READ) != 0)
- be_pair_transfer(partner, bev, 1);
-
- if ((iotype & EV_WRITE) != 0)
- be_pair_transfer(bev, partner, 1);
-
- if (mode == BEV_FINISHED) {
- bufferevent_run_eventcb_(partner, iotype|BEV_EVENT_EOF, 0);
- }
- decref_and_unlock(bev);
- return 0;
-}
-
-struct bufferevent *
-bufferevent_pair_get_partner(struct bufferevent *bev)
-{
- struct bufferevent_pair *bev_p;
- struct bufferevent *partner = NULL;
- bev_p = upcast(bev);
- if (! bev_p)
- return NULL;
-
- incref_and_lock(bev);
- if (bev_p->partner)
- partner = downcast(bev_p->partner);
- decref_and_unlock(bev);
- return partner;
-}
-
-const struct bufferevent_ops bufferevent_ops_pair = {
- "pair_elt",
- evutil_offsetof(struct bufferevent_pair, bev.bev),
- be_pair_enable,
- be_pair_disable,
- be_pair_unlink,
- be_pair_destruct,
- bufferevent_generic_adj_timeouts_,
- be_pair_flush,
- NULL, /* ctrl */
-};
diff --git a/libs/libevent/src/bufferevent_ratelim.c b/libs/libevent/src/bufferevent_ratelim.c
deleted file mode 100644
index bde192021b..0000000000
--- a/libs/libevent/src/bufferevent_ratelim.c
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "event2/util.h"
-#include "event2/bufferevent.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/buffer.h"
-
-#include "ratelim-internal.h"
-
-#include "bufferevent-internal.h"
-#include "mm-internal.h"
-#include "util-internal.h"
-#include "event-internal.h"
-
-int
-ev_token_bucket_init_(struct ev_token_bucket *bucket,
- const struct ev_token_bucket_cfg *cfg,
- ev_uint32_t current_tick,
- int reinitialize)
-{
- if (reinitialize) {
- /* on reinitialization, we only clip downwards, since we've
- already used who-knows-how-much bandwidth this tick. We
- leave "last_updated" as it is; the next update will add the
- appropriate amount of bandwidth to the bucket.
- */
- if (bucket->read_limit > (ev_int64_t) cfg->read_maximum)
- bucket->read_limit = cfg->read_maximum;
- if (bucket->write_limit > (ev_int64_t) cfg->write_maximum)
- bucket->write_limit = cfg->write_maximum;
- } else {
- bucket->read_limit = cfg->read_rate;
- bucket->write_limit = cfg->write_rate;
- bucket->last_updated = current_tick;
- }
- return 0;
-}
-
-int
-ev_token_bucket_update_(struct ev_token_bucket *bucket,
- const struct ev_token_bucket_cfg *cfg,
- ev_uint32_t current_tick)
-{
- /* It's okay if the tick number overflows, since we'll just
- * wrap around when we do the unsigned substraction. */
- unsigned n_ticks = current_tick - bucket->last_updated;
-
- /* Make sure some ticks actually happened, and that time didn't
- * roll back. */
- if (n_ticks == 0 || n_ticks > INT_MAX)
- return 0;
-
- /* Naively, we would say
- bucket->limit += n_ticks * cfg->rate;
-
- if (bucket->limit > cfg->maximum)
- bucket->limit = cfg->maximum;
-
- But we're worried about overflow, so we do it like this:
- */
-
- if ((cfg->read_maximum - bucket->read_limit) / n_ticks < cfg->read_rate)
- bucket->read_limit = cfg->read_maximum;
- else
- bucket->read_limit += n_ticks * cfg->read_rate;
-
-
- if ((cfg->write_maximum - bucket->write_limit) / n_ticks < cfg->write_rate)
- bucket->write_limit = cfg->write_maximum;
- else
- bucket->write_limit += n_ticks * cfg->write_rate;
-
-
- bucket->last_updated = current_tick;
-
- return 1;
-}
-
-static inline void
-bufferevent_update_buckets(struct bufferevent_private *bev)
-{
- /* Must hold lock on bev. */
- struct timeval now;
- unsigned tick;
- event_base_gettimeofday_cached(bev->bev.ev_base, &now);
- tick = ev_token_bucket_get_tick_(&now, bev->rate_limiting->cfg);
- if (tick != bev->rate_limiting->limit.last_updated)
- ev_token_bucket_update_(&bev->rate_limiting->limit,
- bev->rate_limiting->cfg, tick);
-}
-
-ev_uint32_t
-ev_token_bucket_get_tick_(const struct timeval *tv,
- const struct ev_token_bucket_cfg *cfg)
-{
- /* This computation uses two multiplies and a divide. We could do
- * fewer if we knew that the tick length was an integer number of
- * seconds, or if we knew it divided evenly into a second. We should
- * investigate that more.
- */
-
- /* We cast to an ev_uint64_t first, since we don't want to overflow
- * before we do the final divide. */
- ev_uint64_t msec = (ev_uint64_t)tv->tv_sec * 1000 + tv->tv_usec / 1000;
- return (unsigned)(msec / cfg->msec_per_tick);
-}
-
-struct ev_token_bucket_cfg *
-ev_token_bucket_cfg_new(size_t read_rate, size_t read_burst,
- size_t write_rate, size_t write_burst,
- const struct timeval *tick_len)
-{
- struct ev_token_bucket_cfg *r;
- struct timeval g;
- if (! tick_len) {
- g.tv_sec = 1;
- g.tv_usec = 0;
- tick_len = &g;
- }
- if (read_rate > read_burst || write_rate > write_burst ||
- read_rate < 1 || write_rate < 1)
- return NULL;
- if (read_rate > EV_RATE_LIMIT_MAX ||
- write_rate > EV_RATE_LIMIT_MAX ||
- read_burst > EV_RATE_LIMIT_MAX ||
- write_burst > EV_RATE_LIMIT_MAX)
- return NULL;
- r = mm_calloc(1, sizeof(struct ev_token_bucket_cfg));
- if (!r)
- return NULL;
- r->read_rate = read_rate;
- r->write_rate = write_rate;
- r->read_maximum = read_burst;
- r->write_maximum = write_burst;
- memcpy(&r->tick_timeout, tick_len, sizeof(struct timeval));
- r->msec_per_tick = (tick_len->tv_sec * 1000) +
- (tick_len->tv_usec & COMMON_TIMEOUT_MICROSECONDS_MASK)/1000;
- return r;
-}
-
-void
-ev_token_bucket_cfg_free(struct ev_token_bucket_cfg *cfg)
-{
- mm_free(cfg);
-}
-
-/* Default values for max_single_read & max_single_write variables. */
-#define MAX_SINGLE_READ_DEFAULT 16384
-#define MAX_SINGLE_WRITE_DEFAULT 16384
-
-#define LOCK_GROUP(g) EVLOCK_LOCK((g)->lock, 0)
-#define UNLOCK_GROUP(g) EVLOCK_UNLOCK((g)->lock, 0)
-
-static int bev_group_suspend_reading_(struct bufferevent_rate_limit_group *g);
-static int bev_group_suspend_writing_(struct bufferevent_rate_limit_group *g);
-static void bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group *g);
-static void bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group *g);
-
-/** Helper: figure out the maximum amount we should write if is_write, or
- the maximum amount we should read if is_read. Return that maximum, or
- 0 if our bucket is wholly exhausted.
- */
-static inline ev_ssize_t
-bufferevent_get_rlim_max_(struct bufferevent_private *bev, int is_write)
-{
- /* needs lock on bev. */
- ev_ssize_t max_so_far = is_write?bev->max_single_write:bev->max_single_read;
-
-#define LIM(x) \
- (is_write ? (x).write_limit : (x).read_limit)
-
-#define GROUP_SUSPENDED(g) \
- (is_write ? (g)->write_suspended : (g)->read_suspended)
-
- /* Sets max_so_far to MIN(x, max_so_far) */
-#define CLAMPTO(x) \
- do { \
- if (max_so_far > (x)) \
- max_so_far = (x); \
- } while (0);
-
- if (!bev->rate_limiting)
- return max_so_far;
-
- /* If rate-limiting is enabled at all, update the appropriate
- bucket, and take the smaller of our rate limit and the group
- rate limit.
- */
-
- if (bev->rate_limiting->cfg) {
- bufferevent_update_buckets(bev);
- max_so_far = LIM(bev->rate_limiting->limit);
- }
- if (bev->rate_limiting->group) {
- struct bufferevent_rate_limit_group *g =
- bev->rate_limiting->group;
- ev_ssize_t share;
- LOCK_GROUP(g);
- if (GROUP_SUSPENDED(g)) {
- /* We can get here if we failed to lock this
- * particular bufferevent while suspending the whole
- * group. */
- if (is_write)
- bufferevent_suspend_write_(&bev->bev,
- BEV_SUSPEND_BW_GROUP);
- else
- bufferevent_suspend_read_(&bev->bev,
- BEV_SUSPEND_BW_GROUP);
- share = 0;
- } else {
- /* XXXX probably we should divide among the active
- * members, not the total members. */
- share = LIM(g->rate_limit) / g->n_members;
- if (share < g->min_share)
- share = g->min_share;
- }
- UNLOCK_GROUP(g);
- CLAMPTO(share);
- }
-
- if (max_so_far < 0)
- max_so_far = 0;
- return max_so_far;
-}
-
-ev_ssize_t
-bufferevent_get_read_max_(struct bufferevent_private *bev)
-{
- return bufferevent_get_rlim_max_(bev, 0);
-}
-
-ev_ssize_t
-bufferevent_get_write_max_(struct bufferevent_private *bev)
-{
- return bufferevent_get_rlim_max_(bev, 1);
-}
-
-int
-bufferevent_decrement_read_buckets_(struct bufferevent_private *bev, ev_ssize_t bytes)
-{
- /* XXXXX Make sure all users of this function check its return value */
- int r = 0;
- /* need to hold lock on bev */
- if (!bev->rate_limiting)
- return 0;
-
- if (bev->rate_limiting->cfg) {
- bev->rate_limiting->limit.read_limit -= bytes;
- if (bev->rate_limiting->limit.read_limit <= 0) {
- bufferevent_suspend_read_(&bev->bev, BEV_SUSPEND_BW);
- if (event_add(&bev->rate_limiting->refill_bucket_event,
- &bev->rate_limiting->cfg->tick_timeout) < 0)
- r = -1;
- } else if (bev->read_suspended & BEV_SUSPEND_BW) {
- if (!(bev->write_suspended & BEV_SUSPEND_BW))
- event_del(&bev->rate_limiting->refill_bucket_event);
- bufferevent_unsuspend_read_(&bev->bev, BEV_SUSPEND_BW);
- }
- }
-
- if (bev->rate_limiting->group) {
- LOCK_GROUP(bev->rate_limiting->group);
- bev->rate_limiting->group->rate_limit.read_limit -= bytes;
- bev->rate_limiting->group->total_read += bytes;
- if (bev->rate_limiting->group->rate_limit.read_limit <= 0) {
- bev_group_suspend_reading_(bev->rate_limiting->group);
- } else if (bev->rate_limiting->group->read_suspended) {
- bev_group_unsuspend_reading_(bev->rate_limiting->group);
- }
- UNLOCK_GROUP(bev->rate_limiting->group);
- }
-
- return r;
-}
-
-int
-bufferevent_decrement_write_buckets_(struct bufferevent_private *bev, ev_ssize_t bytes)
-{
- /* XXXXX Make sure all users of this function check its return value */
- int r = 0;
- /* need to hold lock */
- if (!bev->rate_limiting)
- return 0;
-
- if (bev->rate_limiting->cfg) {
- bev->rate_limiting->limit.write_limit -= bytes;
- if (bev->rate_limiting->limit.write_limit <= 0) {
- bufferevent_suspend_write_(&bev->bev, BEV_SUSPEND_BW);
- if (event_add(&bev->rate_limiting->refill_bucket_event,
- &bev->rate_limiting->cfg->tick_timeout) < 0)
- r = -1;
- } else if (bev->write_suspended & BEV_SUSPEND_BW) {
- if (!(bev->read_suspended & BEV_SUSPEND_BW))
- event_del(&bev->rate_limiting->refill_bucket_event);
- bufferevent_unsuspend_write_(&bev->bev, BEV_SUSPEND_BW);
- }
- }
-
- if (bev->rate_limiting->group) {
- LOCK_GROUP(bev->rate_limiting->group);
- bev->rate_limiting->group->rate_limit.write_limit -= bytes;
- bev->rate_limiting->group->total_written += bytes;
- if (bev->rate_limiting->group->rate_limit.write_limit <= 0) {
- bev_group_suspend_writing_(bev->rate_limiting->group);
- } else if (bev->rate_limiting->group->write_suspended) {
- bev_group_unsuspend_writing_(bev->rate_limiting->group);
- }
- UNLOCK_GROUP(bev->rate_limiting->group);
- }
-
- return r;
-}
-
-/** Stop reading on every bufferevent in <b>g</b> */
-static int
-bev_group_suspend_reading_(struct bufferevent_rate_limit_group *g)
-{
- /* Needs group lock */
- struct bufferevent_private *bev;
- g->read_suspended = 1;
- g->pending_unsuspend_read = 0;
-
- /* Note that in this loop we call EVLOCK_TRY_LOCK_ instead of BEV_LOCK,
- to prevent a deadlock. (Ordinarily, the group lock nests inside
- the bufferevent locks. If we are unable to lock any individual
- bufferevent, it will find out later when it looks at its limit
- and sees that its group is suspended.)
- */
- LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) {
- if (EVLOCK_TRY_LOCK_(bev->lock)) {
- bufferevent_suspend_read_(&bev->bev,
- BEV_SUSPEND_BW_GROUP);
- EVLOCK_UNLOCK(bev->lock, 0);
- }
- }
- return 0;
-}
-
-/** Stop writing on every bufferevent in <b>g</b> */
-static int
-bev_group_suspend_writing_(struct bufferevent_rate_limit_group *g)
-{
- /* Needs group lock */
- struct bufferevent_private *bev;
- g->write_suspended = 1;
- g->pending_unsuspend_write = 0;
- LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) {
- if (EVLOCK_TRY_LOCK_(bev->lock)) {
- bufferevent_suspend_write_(&bev->bev,
- BEV_SUSPEND_BW_GROUP);
- EVLOCK_UNLOCK(bev->lock, 0);
- }
- }
- return 0;
-}
-
-/** Timer callback invoked on a single bufferevent with one or more exhausted
- buckets when they are ready to refill. */
-static void
-bev_refill_callback_(evutil_socket_t fd, short what, void *arg)
-{
- unsigned tick;
- struct timeval now;
- struct bufferevent_private *bev = arg;
- int again = 0;
- BEV_LOCK(&bev->bev);
- if (!bev->rate_limiting || !bev->rate_limiting->cfg) {
- BEV_UNLOCK(&bev->bev);
- return;
- }
-
- /* First, update the bucket */
- event_base_gettimeofday_cached(bev->bev.ev_base, &now);
- tick = ev_token_bucket_get_tick_(&now,
- bev->rate_limiting->cfg);
- ev_token_bucket_update_(&bev->rate_limiting->limit,
- bev->rate_limiting->cfg,
- tick);
-
- /* Now unsuspend any read/write operations as appropriate. */
- if ((bev->read_suspended & BEV_SUSPEND_BW)) {
- if (bev->rate_limiting->limit.read_limit > 0)
- bufferevent_unsuspend_read_(&bev->bev, BEV_SUSPEND_BW);
- else
- again = 1;
- }
- if ((bev->write_suspended & BEV_SUSPEND_BW)) {
- if (bev->rate_limiting->limit.write_limit > 0)
- bufferevent_unsuspend_write_(&bev->bev, BEV_SUSPEND_BW);
- else
- again = 1;
- }
- if (again) {
- /* One or more of the buckets may need another refill if they
- started negative.
-
- XXXX if we need to be quiet for more ticks, we should
- maybe figure out what timeout we really want.
- */
- /* XXXX Handle event_add failure somehow */
- event_add(&bev->rate_limiting->refill_bucket_event,
- &bev->rate_limiting->cfg->tick_timeout);
- }
- BEV_UNLOCK(&bev->bev);
-}
-
-/** Helper: grab a random element from a bufferevent group.
- *
- * Requires that we hold the lock on the group.
- */
-static struct bufferevent_private *
-bev_group_random_element_(struct bufferevent_rate_limit_group *group)
-{
- int which;
- struct bufferevent_private *bev;
-
- /* requires group lock */
-
- if (!group->n_members)
- return NULL;
-
- EVUTIL_ASSERT(! LIST_EMPTY(&group->members));
-
- which = evutil_weakrand_range_(&group->weakrand_seed, group->n_members);
-
- bev = LIST_FIRST(&group->members);
- while (which--)
- bev = LIST_NEXT(bev, rate_limiting->next_in_group);
-
- return bev;
-}
-
-/** Iterate over the elements of a rate-limiting group 'g' with a random
- starting point, assigning each to the variable 'bev', and executing the
- block 'block'.
-
- We do this in a half-baked effort to get fairness among group members.
- XXX Round-robin or some kind of priority queue would be even more fair.
- */
-#define FOREACH_RANDOM_ORDER(block) \
- do { \
- first = bev_group_random_element_(g); \
- for (bev = first; bev != LIST_END(&g->members); \
- bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \
- block ; \
- } \
- for (bev = LIST_FIRST(&g->members); bev && bev != first; \
- bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \
- block ; \
- } \
- } while (0)
-
-static void
-bev_group_unsuspend_reading_(struct bufferevent_rate_limit_group *g)
-{
- int again = 0;
- struct bufferevent_private *bev, *first;
-
- g->read_suspended = 0;
- FOREACH_RANDOM_ORDER({
- if (EVLOCK_TRY_LOCK_(bev->lock)) {
- bufferevent_unsuspend_read_(&bev->bev,
- BEV_SUSPEND_BW_GROUP);
- EVLOCK_UNLOCK(bev->lock, 0);
- } else {
- again = 1;
- }
- });
- g->pending_unsuspend_read = again;
-}
-
-static void
-bev_group_unsuspend_writing_(struct bufferevent_rate_limit_group *g)
-{
- int again = 0;
- struct bufferevent_private *bev, *first;
- g->write_suspended = 0;
-
- FOREACH_RANDOM_ORDER({
- if (EVLOCK_TRY_LOCK_(bev->lock)) {
- bufferevent_unsuspend_write_(&bev->bev,
- BEV_SUSPEND_BW_GROUP);
- EVLOCK_UNLOCK(bev->lock, 0);
- } else {
- again = 1;
- }
- });
- g->pending_unsuspend_write = again;
-}
-
-/** Callback invoked every tick to add more elements to the group bucket
- and unsuspend group members as needed.
- */
-static void
-bev_group_refill_callback_(evutil_socket_t fd, short what, void *arg)
-{
- struct bufferevent_rate_limit_group *g = arg;
- unsigned tick;
- struct timeval now;
-
- event_base_gettimeofday_cached(event_get_base(&g->master_refill_event), &now);
-
- LOCK_GROUP(g);
-
- tick = ev_token_bucket_get_tick_(&now, &g->rate_limit_cfg);
- ev_token_bucket_update_(&g->rate_limit, &g->rate_limit_cfg, tick);
-
- if (g->pending_unsuspend_read ||
- (g->read_suspended && (g->rate_limit.read_limit >= g->min_share))) {
- bev_group_unsuspend_reading_(g);
- }
- if (g->pending_unsuspend_write ||
- (g->write_suspended && (g->rate_limit.write_limit >= g->min_share))){
- bev_group_unsuspend_writing_(g);
- }
-
- /* XXXX Rather than waiting to the next tick to unsuspend stuff
- * with pending_unsuspend_write/read, we should do it on the
- * next iteration of the mainloop.
- */
-
- UNLOCK_GROUP(g);
-}
-
-int
-bufferevent_set_rate_limit(struct bufferevent *bev,
- struct ev_token_bucket_cfg *cfg)
-{
- struct bufferevent_private *bevp =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
- int r = -1;
- struct bufferevent_rate_limit *rlim;
- struct timeval now;
- ev_uint32_t tick;
- int reinit = 0, suspended = 0;
- /* XXX reference-count cfg */
-
- BEV_LOCK(bev);
-
- if (cfg == NULL) {
- if (bevp->rate_limiting) {
- rlim = bevp->rate_limiting;
- rlim->cfg = NULL;
- bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
- bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
- if (event_initialized(&rlim->refill_bucket_event))
- event_del(&rlim->refill_bucket_event);
- }
- r = 0;
- goto done;
- }
-
- event_base_gettimeofday_cached(bev->ev_base, &now);
- tick = ev_token_bucket_get_tick_(&now, cfg);
-
- if (bevp->rate_limiting && bevp->rate_limiting->cfg == cfg) {
- /* no-op */
- r = 0;
- goto done;
- }
- if (bevp->rate_limiting == NULL) {
- rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
- if (!rlim)
- goto done;
- bevp->rate_limiting = rlim;
- } else {
- rlim = bevp->rate_limiting;
- }
- reinit = rlim->cfg != NULL;
-
- rlim->cfg = cfg;
- ev_token_bucket_init_(&rlim->limit, cfg, tick, reinit);
-
- if (reinit) {
- EVUTIL_ASSERT(event_initialized(&rlim->refill_bucket_event));
- event_del(&rlim->refill_bucket_event);
- }
- event_assign(&rlim->refill_bucket_event, bev->ev_base,
- -1, EV_FINALIZE, bev_refill_callback_, bevp);
-
- if (rlim->limit.read_limit > 0) {
- bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
- } else {
- bufferevent_suspend_read_(bev, BEV_SUSPEND_BW);
- suspended=1;
- }
- if (rlim->limit.write_limit > 0) {
- bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
- } else {
- bufferevent_suspend_write_(bev, BEV_SUSPEND_BW);
- suspended = 1;
- }
-
- if (suspended)
- event_add(&rlim->refill_bucket_event, &cfg->tick_timeout);
-
- r = 0;
-
-done:
- BEV_UNLOCK(bev);
- return r;
-}
-
-struct bufferevent_rate_limit_group *
-bufferevent_rate_limit_group_new(struct event_base *base,
- const struct ev_token_bucket_cfg *cfg)
-{
- struct bufferevent_rate_limit_group *g;
- struct timeval now;
- ev_uint32_t tick;
-
- event_base_gettimeofday_cached(base, &now);
- tick = ev_token_bucket_get_tick_(&now, cfg);
-
- g = mm_calloc(1, sizeof(struct bufferevent_rate_limit_group));
- if (!g)
- return NULL;
- memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg));
- LIST_INIT(&g->members);
-
- ev_token_bucket_init_(&g->rate_limit, cfg, tick, 0);
-
- event_assign(&g->master_refill_event, base, -1, EV_PERSIST|EV_FINALIZE,
- bev_group_refill_callback_, g);
- /*XXXX handle event_add failure */
- event_add(&g->master_refill_event, &cfg->tick_timeout);
-
- EVTHREAD_ALLOC_LOCK(g->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
-
- bufferevent_rate_limit_group_set_min_share(g, 64);
-
- evutil_weakrand_seed_(&g->weakrand_seed,
- (ev_uint32_t) ((now.tv_sec + now.tv_usec) + (ev_intptr_t)g));
-
- return g;
-}
-
-int
-bufferevent_rate_limit_group_set_cfg(
- struct bufferevent_rate_limit_group *g,
- const struct ev_token_bucket_cfg *cfg)
-{
- int same_tick;
- if (!g || !cfg)
- return -1;
-
- LOCK_GROUP(g);
- same_tick = evutil_timercmp(
- &g->rate_limit_cfg.tick_timeout, &cfg->tick_timeout, ==);
- memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg));
-
- if (g->rate_limit.read_limit > (ev_ssize_t)cfg->read_maximum)
- g->rate_limit.read_limit = cfg->read_maximum;
- if (g->rate_limit.write_limit > (ev_ssize_t)cfg->write_maximum)
- g->rate_limit.write_limit = cfg->write_maximum;
-
- if (!same_tick) {
- /* This can cause a hiccup in the schedule */
- event_add(&g->master_refill_event, &cfg->tick_timeout);
- }
-
- /* The new limits might force us to adjust min_share differently. */
- bufferevent_rate_limit_group_set_min_share(g, g->configured_min_share);
-
- UNLOCK_GROUP(g);
- return 0;
-}
-
-int
-bufferevent_rate_limit_group_set_min_share(
- struct bufferevent_rate_limit_group *g,
- size_t share)
-{
- if (share > EV_SSIZE_MAX)
- return -1;
-
- g->configured_min_share = share;
-
- /* Can't set share to less than the one-tick maximum. IOW, at steady
- * state, at least one connection can go per tick. */
- if (share > g->rate_limit_cfg.read_rate)
- share = g->rate_limit_cfg.read_rate;
- if (share > g->rate_limit_cfg.write_rate)
- share = g->rate_limit_cfg.write_rate;
-
- g->min_share = share;
- return 0;
-}
-
-void
-bufferevent_rate_limit_group_free(struct bufferevent_rate_limit_group *g)
-{
- LOCK_GROUP(g);
- EVUTIL_ASSERT(0 == g->n_members);
- event_del(&g->master_refill_event);
- UNLOCK_GROUP(g);
- EVTHREAD_FREE_LOCK(g->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- mm_free(g);
-}
-
-int
-bufferevent_add_to_rate_limit_group(struct bufferevent *bev,
- struct bufferevent_rate_limit_group *g)
-{
- int wsuspend, rsuspend;
- struct bufferevent_private *bevp =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
- BEV_LOCK(bev);
-
- if (!bevp->rate_limiting) {
- struct bufferevent_rate_limit *rlim;
- rlim = mm_calloc(1, sizeof(struct bufferevent_rate_limit));
- if (!rlim) {
- BEV_UNLOCK(bev);
- return -1;
- }
- event_assign(&rlim->refill_bucket_event, bev->ev_base,
- -1, EV_FINALIZE, bev_refill_callback_, bevp);
- bevp->rate_limiting = rlim;
- }
-
- if (bevp->rate_limiting->group == g) {
- BEV_UNLOCK(bev);
- return 0;
- }
- if (bevp->rate_limiting->group)
- bufferevent_remove_from_rate_limit_group(bev);
-
- LOCK_GROUP(g);
- bevp->rate_limiting->group = g;
- ++g->n_members;
- LIST_INSERT_HEAD(&g->members, bevp, rate_limiting->next_in_group);
-
- rsuspend = g->read_suspended;
- wsuspend = g->write_suspended;
-
- UNLOCK_GROUP(g);
-
- if (rsuspend)
- bufferevent_suspend_read_(bev, BEV_SUSPEND_BW_GROUP);
- if (wsuspend)
- bufferevent_suspend_write_(bev, BEV_SUSPEND_BW_GROUP);
-
- BEV_UNLOCK(bev);
- return 0;
-}
-
-int
-bufferevent_remove_from_rate_limit_group(struct bufferevent *bev)
-{
- return bufferevent_remove_from_rate_limit_group_internal_(bev, 1);
-}
-
-int
-bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev,
- int unsuspend)
-{
- struct bufferevent_private *bevp =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
- BEV_LOCK(bev);
- if (bevp->rate_limiting && bevp->rate_limiting->group) {
- struct bufferevent_rate_limit_group *g =
- bevp->rate_limiting->group;
- LOCK_GROUP(g);
- bevp->rate_limiting->group = NULL;
- --g->n_members;
- LIST_REMOVE(bevp, rate_limiting->next_in_group);
- UNLOCK_GROUP(g);
- }
- if (unsuspend) {
- bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW_GROUP);
- bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW_GROUP);
- }
- BEV_UNLOCK(bev);
- return 0;
-}
-
-/* ===
- * API functions to expose rate limits.
- *
- * Don't use these from inside Libevent; they're meant to be for use by
- * the program.
- * === */
-
-/* Mostly you don't want to use this function from inside libevent;
- * bufferevent_get_read_max_() is more likely what you want*/
-ev_ssize_t
-bufferevent_get_read_limit(struct bufferevent *bev)
-{
- ev_ssize_t r;
- struct bufferevent_private *bevp;
- BEV_LOCK(bev);
- bevp = BEV_UPCAST(bev);
- if (bevp->rate_limiting && bevp->rate_limiting->cfg) {
- bufferevent_update_buckets(bevp);
- r = bevp->rate_limiting->limit.read_limit;
- } else {
- r = EV_SSIZE_MAX;
- }
- BEV_UNLOCK(bev);
- return r;
-}
-
-/* Mostly you don't want to use this function from inside libevent;
- * bufferevent_get_write_max_() is more likely what you want*/
-ev_ssize_t
-bufferevent_get_write_limit(struct bufferevent *bev)
-{
- ev_ssize_t r;
- struct bufferevent_private *bevp;
- BEV_LOCK(bev);
- bevp = BEV_UPCAST(bev);
- if (bevp->rate_limiting && bevp->rate_limiting->cfg) {
- bufferevent_update_buckets(bevp);
- r = bevp->rate_limiting->limit.write_limit;
- } else {
- r = EV_SSIZE_MAX;
- }
- BEV_UNLOCK(bev);
- return r;
-}
-
-int
-bufferevent_set_max_single_read(struct bufferevent *bev, size_t size)
-{
- struct bufferevent_private *bevp;
- BEV_LOCK(bev);
- bevp = BEV_UPCAST(bev);
- if (size == 0 || size > EV_SSIZE_MAX)
- bevp->max_single_read = MAX_SINGLE_READ_DEFAULT;
- else
- bevp->max_single_read = size;
- BEV_UNLOCK(bev);
- return 0;
-}
-
-int
-bufferevent_set_max_single_write(struct bufferevent *bev, size_t size)
-{
- struct bufferevent_private *bevp;
- BEV_LOCK(bev);
- bevp = BEV_UPCAST(bev);
- if (size == 0 || size > EV_SSIZE_MAX)
- bevp->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
- else
- bevp->max_single_write = size;
- BEV_UNLOCK(bev);
- return 0;
-}
-
-ev_ssize_t
-bufferevent_get_max_single_read(struct bufferevent *bev)
-{
- ev_ssize_t r;
-
- BEV_LOCK(bev);
- r = BEV_UPCAST(bev)->max_single_read;
- BEV_UNLOCK(bev);
- return r;
-}
-
-ev_ssize_t
-bufferevent_get_max_single_write(struct bufferevent *bev)
-{
- ev_ssize_t r;
-
- BEV_LOCK(bev);
- r = BEV_UPCAST(bev)->max_single_write;
- BEV_UNLOCK(bev);
- return r;
-}
-
-ev_ssize_t
-bufferevent_get_max_to_read(struct bufferevent *bev)
-{
- ev_ssize_t r;
- BEV_LOCK(bev);
- r = bufferevent_get_read_max_(BEV_UPCAST(bev));
- BEV_UNLOCK(bev);
- return r;
-}
-
-ev_ssize_t
-bufferevent_get_max_to_write(struct bufferevent *bev)
-{
- ev_ssize_t r;
- BEV_LOCK(bev);
- r = bufferevent_get_write_max_(BEV_UPCAST(bev));
- BEV_UNLOCK(bev);
- return r;
-}
-
-const struct ev_token_bucket_cfg *
-bufferevent_get_token_bucket_cfg(const struct bufferevent *bev) {
- struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
- struct ev_token_bucket_cfg *cfg;
-
- BEV_LOCK(bev);
-
- if (bufev_private->rate_limiting) {
- cfg = bufev_private->rate_limiting->cfg;
- } else {
- cfg = NULL;
- }
-
- BEV_UNLOCK(bev);
-
- return cfg;
-}
-
-/* Mostly you don't want to use this function from inside libevent;
- * bufferevent_get_read_max_() is more likely what you want*/
-ev_ssize_t
-bufferevent_rate_limit_group_get_read_limit(
- struct bufferevent_rate_limit_group *grp)
-{
- ev_ssize_t r;
- LOCK_GROUP(grp);
- r = grp->rate_limit.read_limit;
- UNLOCK_GROUP(grp);
- return r;
-}
-
-/* Mostly you don't want to use this function from inside libevent;
- * bufferevent_get_write_max_() is more likely what you want. */
-ev_ssize_t
-bufferevent_rate_limit_group_get_write_limit(
- struct bufferevent_rate_limit_group *grp)
-{
- ev_ssize_t r;
- LOCK_GROUP(grp);
- r = grp->rate_limit.write_limit;
- UNLOCK_GROUP(grp);
- return r;
-}
-
-int
-bufferevent_decrement_read_limit(struct bufferevent *bev, ev_ssize_t decr)
-{
- int r = 0;
- ev_ssize_t old_limit, new_limit;
- struct bufferevent_private *bevp;
- BEV_LOCK(bev);
- bevp = BEV_UPCAST(bev);
- EVUTIL_ASSERT(bevp->rate_limiting && bevp->rate_limiting->cfg);
- old_limit = bevp->rate_limiting->limit.read_limit;
-
- new_limit = (bevp->rate_limiting->limit.read_limit -= decr);
- if (old_limit > 0 && new_limit <= 0) {
- bufferevent_suspend_read_(bev, BEV_SUSPEND_BW);
- if (event_add(&bevp->rate_limiting->refill_bucket_event,
- &bevp->rate_limiting->cfg->tick_timeout) < 0)
- r = -1;
- } else if (old_limit <= 0 && new_limit > 0) {
- if (!(bevp->write_suspended & BEV_SUSPEND_BW))
- event_del(&bevp->rate_limiting->refill_bucket_event);
- bufferevent_unsuspend_read_(bev, BEV_SUSPEND_BW);
- }
-
- BEV_UNLOCK(bev);
- return r;
-}
-
-int
-bufferevent_decrement_write_limit(struct bufferevent *bev, ev_ssize_t decr)
-{
- /* XXXX this is mostly copy-and-paste from
- * bufferevent_decrement_read_limit */
- int r = 0;
- ev_ssize_t old_limit, new_limit;
- struct bufferevent_private *bevp;
- BEV_LOCK(bev);
- bevp = BEV_UPCAST(bev);
- EVUTIL_ASSERT(bevp->rate_limiting && bevp->rate_limiting->cfg);
- old_limit = bevp->rate_limiting->limit.write_limit;
-
- new_limit = (bevp->rate_limiting->limit.write_limit -= decr);
- if (old_limit > 0 && new_limit <= 0) {
- bufferevent_suspend_write_(bev, BEV_SUSPEND_BW);
- if (event_add(&bevp->rate_limiting->refill_bucket_event,
- &bevp->rate_limiting->cfg->tick_timeout) < 0)
- r = -1;
- } else if (old_limit <= 0 && new_limit > 0) {
- if (!(bevp->read_suspended & BEV_SUSPEND_BW))
- event_del(&bevp->rate_limiting->refill_bucket_event);
- bufferevent_unsuspend_write_(bev, BEV_SUSPEND_BW);
- }
-
- BEV_UNLOCK(bev);
- return r;
-}
-
-int
-bufferevent_rate_limit_group_decrement_read(
- struct bufferevent_rate_limit_group *grp, ev_ssize_t decr)
-{
- int r = 0;
- ev_ssize_t old_limit, new_limit;
- LOCK_GROUP(grp);
- old_limit = grp->rate_limit.read_limit;
- new_limit = (grp->rate_limit.read_limit -= decr);
-
- if (old_limit > 0 && new_limit <= 0) {
- bev_group_suspend_reading_(grp);
- } else if (old_limit <= 0 && new_limit > 0) {
- bev_group_unsuspend_reading_(grp);
- }
-
- UNLOCK_GROUP(grp);
- return r;
-}
-
-int
-bufferevent_rate_limit_group_decrement_write(
- struct bufferevent_rate_limit_group *grp, ev_ssize_t decr)
-{
- int r = 0;
- ev_ssize_t old_limit, new_limit;
- LOCK_GROUP(grp);
- old_limit = grp->rate_limit.write_limit;
- new_limit = (grp->rate_limit.write_limit -= decr);
-
- if (old_limit > 0 && new_limit <= 0) {
- bev_group_suspend_writing_(grp);
- } else if (old_limit <= 0 && new_limit > 0) {
- bev_group_unsuspend_writing_(grp);
- }
-
- UNLOCK_GROUP(grp);
- return r;
-}
-
-void
-bufferevent_rate_limit_group_get_totals(struct bufferevent_rate_limit_group *grp,
- ev_uint64_t *total_read_out, ev_uint64_t *total_written_out)
-{
- EVUTIL_ASSERT(grp != NULL);
- if (total_read_out)
- *total_read_out = grp->total_read;
- if (total_written_out)
- *total_written_out = grp->total_written;
-}
-
-void
-bufferevent_rate_limit_group_reset_totals(struct bufferevent_rate_limit_group *grp)
-{
- grp->total_read = grp->total_written = 0;
-}
-
-int
-bufferevent_ratelim_init_(struct bufferevent_private *bev)
-{
- bev->rate_limiting = NULL;
- bev->max_single_read = MAX_SINGLE_READ_DEFAULT;
- bev->max_single_write = MAX_SINGLE_WRITE_DEFAULT;
-
- return 0;
-}
diff --git a/libs/libevent/src/bufferevent_sock.c b/libs/libevent/src/bufferevent_sock.c
deleted file mode 100644
index a2b381ac4d..0000000000
--- a/libs/libevent/src/bufferevent_sock.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_STDARG_H
-#include <stdarg.h>
-#endif
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef EVENT__HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef EVENT__HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-
-#include "event2/util.h"
-#include "event2/bufferevent.h"
-#include "event2/buffer.h"
-#include "event2/bufferevent_struct.h"
-#include "event2/bufferevent_compat.h"
-#include "event2/event.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "bufferevent-internal.h"
-#include "util-internal.h"
-#ifdef _WIN32
-#include "iocp-internal.h"
-#endif
-
-/* prototypes */
-static int be_socket_enable(struct bufferevent *, short);
-static int be_socket_disable(struct bufferevent *, short);
-static void be_socket_destruct(struct bufferevent *);
-static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode);
-static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *);
-
-static void be_socket_setfd(struct bufferevent *, evutil_socket_t);
-
-const struct bufferevent_ops bufferevent_ops_socket = {
- "socket",
- evutil_offsetof(struct bufferevent_private, bev),
- be_socket_enable,
- be_socket_disable,
- NULL, /* unlink */
- be_socket_destruct,
- bufferevent_generic_adj_existing_timeouts_,
- be_socket_flush,
- be_socket_ctrl,
-};
-
-const struct sockaddr*
-bufferevent_socket_get_conn_address_(struct bufferevent *bev)
-{
- struct bufferevent_private *bev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
-
- return (struct sockaddr *)&bev_p->conn_address;
-}
-static void
-bufferevent_socket_set_conn_address_fd(struct bufferevent_private *bev_p, int fd)
-{
- socklen_t len = sizeof(bev_p->conn_address);
-
- struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address;
- if (addr->sa_family != AF_UNSPEC)
- getpeername(fd, addr, &len);
-}
-static void
-bufferevent_socket_set_conn_address(struct bufferevent_private *bev_p,
- struct sockaddr *addr, size_t addrlen)
-{
- EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address));
- memcpy(&bev_p->conn_address, addr, addrlen);
-}
-
-static void
-bufferevent_socket_outbuf_cb(struct evbuffer *buf,
- const struct evbuffer_cb_info *cbinfo,
- void *arg)
-{
- struct bufferevent *bufev = arg;
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
-
- if (cbinfo->n_added &&
- (bufev->enabled & EV_WRITE) &&
- !event_pending(&bufev->ev_write, EV_WRITE, NULL) &&
- !bufev_p->write_suspended) {
- /* Somebody added data to the buffer, and we would like to
- * write, and we were not writing. So, start writing. */
- if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) {
- /* Should we log this? */
- }
- }
-}
-
-static void
-bufferevent_readcb(evutil_socket_t fd, short event, void *arg)
-{
- struct bufferevent *bufev = arg;
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- struct evbuffer *input;
- int res = 0;
- short what = BEV_EVENT_READING;
- ev_ssize_t howmuch = -1, readmax=-1;
-
- bufferevent_incref_and_lock_(bufev);
-
- if (event == EV_TIMEOUT) {
- /* Note that we only check for event==EV_TIMEOUT. If
- * event==EV_TIMEOUT|EV_READ, we can safely ignore the
- * timeout, since a read has occurred */
- what |= BEV_EVENT_TIMEOUT;
- goto error;
- }
-
- input = bufev->input;
-
- /*
- * If we have a high watermark configured then we don't want to
- * read more data than would make us reach the watermark.
- */
- if (bufev->wm_read.high != 0) {
- howmuch = bufev->wm_read.high - evbuffer_get_length(input);
- /* we somehow lowered the watermark, stop reading */
- if (howmuch <= 0) {
- bufferevent_wm_suspend_read(bufev);
- goto done;
- }
- }
- readmax = bufferevent_get_read_max_(bufev_p);
- if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited"
- * uglifies this code. XXXX */
- howmuch = readmax;
- if (bufev_p->read_suspended)
- goto done;
-
- evbuffer_unfreeze(input, 0);
- res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */
- evbuffer_freeze(input, 0);
-
- if (res == -1) {
- int err = evutil_socket_geterror(fd);
- if (EVUTIL_ERR_RW_RETRIABLE(err))
- goto reschedule;
- /* error case */
- what |= BEV_EVENT_ERROR;
- } else if (res == 0) {
- /* eof case */
- what |= BEV_EVENT_EOF;
- }
-
- if (res <= 0)
- goto error;
-
- bufferevent_decrement_read_buckets_(bufev_p, res);
-
- /* Invoke the user callback - must always be called last */
- bufferevent_trigger_nolock_(bufev, EV_READ, 0);
-
- goto done;
-
- reschedule:
- goto done;
-
- error:
- bufferevent_disable(bufev, EV_READ);
- bufferevent_run_eventcb_(bufev, what, 0);
-
- done:
- bufferevent_decref_and_unlock_(bufev);
-}
-
-static void
-bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
-{
- struct bufferevent *bufev = arg;
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- int res = 0;
- short what = BEV_EVENT_WRITING;
- int connected = 0;
- ev_ssize_t atmost = -1;
-
- bufferevent_incref_and_lock_(bufev);
-
- if (event == EV_TIMEOUT) {
- /* Note that we only check for event==EV_TIMEOUT. If
- * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the
- * timeout, since a read has occurred */
- what |= BEV_EVENT_TIMEOUT;
- goto error;
- }
- if (bufev_p->connecting) {
- int c = evutil_socket_finished_connecting_(fd);
- /* we need to fake the error if the connection was refused
- * immediately - usually connection to localhost on BSD */
- if (bufev_p->connection_refused) {
- bufev_p->connection_refused = 0;
- c = -1;
- }
-
- if (c == 0)
- goto done;
-
- bufev_p->connecting = 0;
- if (c < 0) {
- event_del(&bufev->ev_write);
- event_del(&bufev->ev_read);
- bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0);
- goto done;
- } else {
- connected = 1;
- bufferevent_socket_set_conn_address_fd(bufev_p, fd);
-#ifdef _WIN32
- if (BEV_IS_ASYNC(bufev)) {
- event_del(&bufev->ev_write);
- bufferevent_async_set_connected_(bufev);
- bufferevent_run_eventcb_(bufev,
- BEV_EVENT_CONNECTED, 0);
- goto done;
- }
-#endif
- bufferevent_run_eventcb_(bufev,
- BEV_EVENT_CONNECTED, 0);
- if (!(bufev->enabled & EV_WRITE) ||
- bufev_p->write_suspended) {
- event_del(&bufev->ev_write);
- goto done;
- }
- }
- }
-
- atmost = bufferevent_get_write_max_(bufev_p);
-
- if (bufev_p->write_suspended)
- goto done;
-
- if (evbuffer_get_length(bufev->output)) {
- evbuffer_unfreeze(bufev->output, 1);
- res = evbuffer_write_atmost(bufev->output, fd, atmost);
- evbuffer_freeze(bufev->output, 1);
- if (res == -1) {
- int err = evutil_socket_geterror(fd);
- if (EVUTIL_ERR_RW_RETRIABLE(err))
- goto reschedule;
- what |= BEV_EVENT_ERROR;
- } else if (res == 0) {
- /* eof case
- XXXX Actually, a 0 on write doesn't indicate
- an EOF. An ECONNRESET might be more typical.
- */
- what |= BEV_EVENT_EOF;
- }
- if (res <= 0)
- goto error;
-
- bufferevent_decrement_write_buckets_(bufev_p, res);
- }
-
- if (evbuffer_get_length(bufev->output) == 0) {
- event_del(&bufev->ev_write);
- }
-
- /*
- * Invoke the user callback if our buffer is drained or below the
- * low watermark.
- */
- if (res || !connected) {
- bufferevent_trigger_nolock_(bufev, EV_WRITE, 0);
- }
-
- goto done;
-
- reschedule:
- if (evbuffer_get_length(bufev->output) == 0) {
- event_del(&bufev->ev_write);
- }
- goto done;
-
- error:
- bufferevent_disable(bufev, EV_WRITE);
- bufferevent_run_eventcb_(bufev, what, 0);
-
- done:
- bufferevent_decref_and_unlock_(bufev);
-}
-
-struct bufferevent *
-bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
- int options)
-{
- struct bufferevent_private *bufev_p;
- struct bufferevent *bufev;
-
-#ifdef _WIN32
- if (base && event_base_get_iocp_(base))
- return bufferevent_async_new_(base, fd, options);
-#endif
-
- if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
- return NULL;
-
- if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket,
- options) < 0) {
- mm_free(bufev_p);
- return NULL;
- }
- bufev = &bufev_p->bev;
- evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);
-
- event_assign(&bufev->ev_read, bufev->ev_base, fd,
- EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
- event_assign(&bufev->ev_write, bufev->ev_base, fd,
- EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
-
- evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);
-
- evbuffer_freeze(bufev->input, 0);
- evbuffer_freeze(bufev->output, 1);
-
- return bufev;
-}
-
-int
-bufferevent_socket_connect(struct bufferevent *bev,
- const struct sockaddr *sa, int socklen)
-{
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
-
- evutil_socket_t fd;
- int r = 0;
- int result=-1;
- int ownfd = 0;
-
- bufferevent_incref_and_lock_(bev);
-
- if (!bufev_p)
- goto done;
-
- fd = bufferevent_getfd(bev);
- if (fd < 0) {
- if (!sa)
- goto done;
- fd = evutil_socket_(sa->sa_family,
- SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
- if (fd < 0)
- goto done;
- ownfd = 1;
- }
- if (sa) {
-#ifdef _WIN32
- if (bufferevent_async_can_connect_(bev)) {
- bufferevent_setfd(bev, fd);
- r = bufferevent_async_connect_(bev, fd, sa, socklen);
- if (r < 0)
- goto freesock;
- bufev_p->connecting = 1;
- result = 0;
- goto done;
- } else
-#endif
- r = evutil_socket_connect_(&fd, sa, socklen);
- if (r < 0)
- goto freesock;
- }
-#ifdef _WIN32
- /* ConnectEx() isn't always around, even when IOCP is enabled.
- * Here, we borrow the socket object's write handler to fall back
- * on a non-blocking connect() when ConnectEx() is unavailable. */
- if (BEV_IS_ASYNC(bev)) {
- event_assign(&bev->ev_write, bev->ev_base, fd,
- EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev);
- }
-#endif
- bufferevent_setfd(bev, fd);
- if (r == 0) {
- if (! be_socket_enable(bev, EV_WRITE)) {
- bufev_p->connecting = 1;
- result = 0;
- goto done;
- }
- } else if (r == 1) {
- /* The connect succeeded already. How very BSD of it. */
- result = 0;
- bufev_p->connecting = 1;
- event_active(&bev->ev_write, EV_WRITE, 1);
- } else {
- /* The connect failed already. How very BSD of it. */
- bufev_p->connection_refused = 1;
- bufev_p->connecting = 1;
- result = 0;
- event_active(&bev->ev_write, EV_WRITE, 1);
- }
-
- goto done;
-
-freesock:
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
- if (ownfd)
- evutil_closesocket(fd);
- /* do something about the error? */
-done:
- bufferevent_decref_and_unlock_(bev);
- return result;
-}
-
-static void
-bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
- void *arg)
-{
- struct bufferevent *bev = arg;
- struct bufferevent_private *bev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
- int r;
- BEV_LOCK(bev);
-
- bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
- bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
-
- if (result != 0) {
- bev_p->dns_error = result;
- bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0);
- bufferevent_decref_and_unlock_(bev);
- if (ai)
- evutil_freeaddrinfo(ai);
- return;
- }
-
- /* XXX use the other addrinfos? */
- /* XXX use this return value */
- bufferevent_socket_set_conn_address(bev_p, ai->ai_addr, (int)ai->ai_addrlen);
- r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
- (void)r;
- bufferevent_decref_and_unlock_(bev);
- evutil_freeaddrinfo(ai);
-}
-
-int
-bufferevent_socket_connect_hostname(struct bufferevent *bev,
- struct evdns_base *evdns_base, int family, const char *hostname, int port)
-{
- char portbuf[10];
- struct evutil_addrinfo hint;
- int err;
- struct bufferevent_private *bev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
-
- if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
- return -1;
- if (port < 1 || port > 65535)
- return -1;
-
- memset(&hint, 0, sizeof(hint));
- hint.ai_family = family;
- hint.ai_protocol = IPPROTO_TCP;
- hint.ai_socktype = SOCK_STREAM;
-
- evutil_snprintf(portbuf, sizeof(portbuf), "%d", port);
-
- BEV_LOCK(bev);
- bev_p->dns_error = 0;
-
- bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP);
- bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP);
-
- bufferevent_incref_(bev);
- err = evutil_getaddrinfo_async_(evdns_base, hostname, portbuf,
- &hint, bufferevent_connect_getaddrinfo_cb, bev);
- BEV_UNLOCK(bev);
-
- if (err == 0) {
- return 0;
- } else {
- bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP);
- bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP);
- bufferevent_decref_(bev);
- return -1;
- }
-}
-
-int
-bufferevent_socket_get_dns_error(struct bufferevent *bev)
-{
- int rv;
- struct bufferevent_private *bev_p =
- EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
-
- BEV_LOCK(bev);
- rv = bev_p->dns_error;
- BEV_UNLOCK(bev);
-
- return rv;
-}
-
-/*
- * 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(evutil_socket_t fd,
- bufferevent_data_cb readcb, bufferevent_data_cb writecb,
- bufferevent_event_cb eventcb, void *cbarg)
-{
- struct bufferevent *bufev;
-
- if (!(bufev = bufferevent_socket_new(NULL, fd, 0)))
- return NULL;
-
- bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg);
-
- return bufev;
-}
-
-
-static int
-be_socket_enable(struct bufferevent *bufev, short event)
-{
- if (event & EV_READ &&
- bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1)
- return -1;
- if (event & EV_WRITE &&
- bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1)
- return -1;
- return 0;
-}
-
-static int
-be_socket_disable(struct bufferevent *bufev, short event)
-{
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- if (event & EV_READ) {
- if (event_del(&bufev->ev_read) == -1)
- return -1;
- }
- /* Don't actually disable the write if we are trying to connect. */
- if ((event & EV_WRITE) && ! bufev_p->connecting) {
- if (event_del(&bufev->ev_write) == -1)
- return -1;
- }
- return 0;
-}
-
-static void
-be_socket_destruct(struct bufferevent *bufev)
-{
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
- evutil_socket_t fd;
- EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
-
- fd = event_get_fd(&bufev->ev_read);
-
- if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
- EVUTIL_CLOSESOCKET(fd);
-}
-
-static int
-be_socket_flush(struct bufferevent *bev, short iotype,
- enum bufferevent_flush_mode mode)
-{
- return 0;
-}
-
-
-static void
-be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd)
-{
- BEV_LOCK(bufev);
- EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
-
- event_del(&bufev->ev_read);
- event_del(&bufev->ev_write);
-
- event_assign(&bufev->ev_read, bufev->ev_base, fd,
- EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
- event_assign(&bufev->ev_write, bufev->ev_base, fd,
- EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
-
- if (fd >= 0)
- bufferevent_enable(bufev, bufev->enabled);
-
- BEV_UNLOCK(bufev);
-}
-
-/* XXXX Should non-socket bufferevents support this? */
-int
-bufferevent_priority_set(struct bufferevent *bufev, int priority)
-{
- int r = -1;
- struct bufferevent_private *bufev_p =
- EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
-
- BEV_LOCK(bufev);
- if (bufev->be_ops != &bufferevent_ops_socket)
- goto done;
-
- if (event_priority_set(&bufev->ev_read, priority) == -1)
- goto done;
- if (event_priority_set(&bufev->ev_write, priority) == -1)
- goto done;
-
- event_deferred_cb_set_priority_(&bufev_p->deferred, priority);
-
- r = 0;
-done:
- BEV_UNLOCK(bufev);
- return r;
-}
-
-/* XXXX Should non-socket bufferevents support this? */
-int
-bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
-{
- int res = -1;
-
- BEV_LOCK(bufev);
- if (bufev->be_ops != &bufferevent_ops_socket)
- goto done;
-
- bufev->ev_base = base;
-
- res = event_base_set(base, &bufev->ev_read);
- if (res == -1)
- goto done;
-
- res = event_base_set(base, &bufev->ev_write);
-done:
- BEV_UNLOCK(bufev);
- return res;
-}
-
-static int
-be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
- union bufferevent_ctrl_data *data)
-{
- switch (op) {
- case BEV_CTRL_SET_FD:
- be_socket_setfd(bev, data->fd);
- return 0;
- case BEV_CTRL_GET_FD:
- data->fd = event_get_fd(&bev->ev_read);
- return 0;
- case BEV_CTRL_GET_UNDERLYING:
- case BEV_CTRL_CANCEL_ALL:
- default:
- return -1;
- }
-}
diff --git a/libs/libevent/src/changelist-internal.h b/libs/libevent/src/changelist-internal.h
deleted file mode 100644
index 98fc52aebf..0000000000
--- a/libs/libevent/src/changelist-internal.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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 CHANGELIST_INTERNAL_H_INCLUDED_
-#define CHANGELIST_INTERNAL_H_INCLUDED_
-
-/*
- A "changelist" is a list of all the fd status changes that should be made
- between calls to the backend's dispatch function. There are a few reasons
- that a backend would want to queue changes like this rather than processing
- them immediately.
-
- 1) Sometimes applications will add and delete the same event more than
- once between calls to dispatch. Processing these changes immediately
- is needless, and potentially expensive (especially if we're on a system
- that makes one syscall per changed event).
-
- 2) Sometimes we can coalesce multiple changes on the same fd into a single
- syscall if we know about them in advance. For example, epoll can do an
- add and a delete at the same time, but only if we have found out about
- both of them before we tell epoll.
-
- 3) Sometimes adding an event that we immediately delete can cause
- unintended consequences: in kqueue, this makes pending events get
- reported spuriously.
- */
-
-#include "event2/util.h"
-
-/** Represents a */
-struct event_change {
- /** The fd or signal whose events are to be changed */
- evutil_socket_t fd;
- /* The events that were enabled on the fd before any of these changes
- were made. May include EV_READ or EV_WRITE. */
- short old_events;
-
- /* The changes that we want to make in reading and writing on this fd.
- * If this is a signal, then read_change has EV_CHANGE_SIGNAL set,
- * and write_change is unused. */
- ev_uint8_t read_change;
- ev_uint8_t write_change;
- ev_uint8_t close_change;
-};
-
-/* Flags for read_change and write_change. */
-
-/* If set, add the event. */
-#define EV_CHANGE_ADD 0x01
-/* If set, delete the event. Exclusive with EV_CHANGE_ADD */
-#define EV_CHANGE_DEL 0x02
-/* If set, this event refers a signal, not an fd. */
-#define EV_CHANGE_SIGNAL EV_SIGNAL
-/* Set for persistent events. Currently not used. */
-#define EV_CHANGE_PERSIST EV_PERSIST
-/* Set for adding edge-triggered events. */
-#define EV_CHANGE_ET EV_ET
-
-/* The value of fdinfo_size that a backend should use if it is letting
- * changelist handle its add and delete functions. */
-#define EVENT_CHANGELIST_FDINFO_SIZE sizeof(int)
-
-/** Set up the data fields in a changelist. */
-void event_changelist_init_(struct event_changelist *changelist);
-/** Remove every change in the changelist, and make corresponding changes
- * in the event maps in the base. This function is generally used right
- * after making all the changes in the changelist. */
-void event_changelist_remove_all_(struct event_changelist *changelist,
- struct event_base *base);
-/** Free all memory held in a changelist. */
-void event_changelist_freemem_(struct event_changelist *changelist);
-
-/** Implementation of eventop_add that queues the event in a changelist. */
-int event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
- void *p);
-/** Implementation of eventop_del that queues the event in a changelist. */
-int event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
- void *p);
-
-#endif
diff --git a/libs/libevent/src/compat/sys/queue.h b/libs/libevent/src/compat/sys/queue.h
deleted file mode 100644
index c387bdcf50..0000000000
--- a/libs/libevent/src/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, headname, field) \
- 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/libs/libevent/src/defer-internal.h b/libs/libevent/src/defer-internal.h
deleted file mode 100644
index e3c7d7da5b..0000000000
--- a/libs/libevent/src/defer-internal.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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 DEFER_INTERNAL_H_INCLUDED_
-#define DEFER_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/queue.h>
-
-struct event_callback;
-typedef void (*deferred_cb_fn)(struct event_callback *, void *);
-
-/**
- Initialize an empty, non-pending event_callback.
-
- @param deferred The struct event_callback structure to initialize.
- @param priority The priority that the callback should run at.
- @param cb The function to run when the struct event_callback executes.
- @param arg The function's second argument.
- */
-void event_deferred_cb_init_(struct event_callback *, ev_uint8_t, deferred_cb_fn, void *);
-/**
- Change the priority of a non-pending event_callback.
- */
-void event_deferred_cb_set_priority_(struct event_callback *, ev_uint8_t);
-/**
- Cancel a struct event_callback if it is currently scheduled in an event_base.
- */
-void event_deferred_cb_cancel_(struct event_base *, struct event_callback *);
-/**
- Activate a struct event_callback if it is not currently scheduled in an event_base.
-
- Return true if it was not previously scheduled.
- */
-int event_deferred_cb_schedule_(struct event_base *, struct event_callback *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* EVENT_INTERNAL_H_INCLUDED_ */
-
diff --git a/libs/libevent/src/epolltable-internal.h b/libs/libevent/src/epolltable-internal.h
deleted file mode 100644
index da30e0973a..0000000000
--- a/libs/libevent/src/epolltable-internal.h
+++ /dev/null
@@ -1,1166 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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 EPOLLTABLE_INTERNAL_H_INCLUDED_
-#define EPOLLTABLE_INTERNAL_H_INCLUDED_
-
-/*
- Here are the values we're masking off to decide what operations to do.
- Note that since EV_READ|EV_WRITE.
-
- Note also that this table is a little sparse, since ADD+DEL is
- nonsensical ("xxx" in the list below.)
-
- Note also also that we are shifting old_events by only 5 bits, since
- EV_READ is 2 and EV_WRITE is 4.
-
- The table was auto-generated with a python script, according to this
- pseudocode:[*0]
-
- If either the read or the write change is add+del:
- This is impossible; Set op==-1, events=0.
- Else, if either the read or the write change is add:
- Set events to 0.
- If the read change is add, or
- (the read change is not del, and ev_read is in old_events):
- Add EPOLLIN to events.
- If the write change is add, or
- (the write change is not del, and ev_write is in old_events):
- Add EPOLLOUT to events.
-
- If old_events is set:
- Set op to EPOLL_CTL_MOD [*1,*2]
- Else:
- Set op to EPOLL_CTL_ADD [*3]
-
- Else, if the read or the write change is del:
- Set op to EPOLL_CTL_DEL.
- If the read change is del:
- If the write change is del:
- Set events to EPOLLIN|EPOLLOUT
- Else if ev_write is in old_events:
- Set events to EPOLLOUT
- Set op to EPOLL_CTL_MOD
- Else
- Set events to EPOLLIN
- Else:
- {The write change is del.}
- If ev_read is in old_events:
- Set events to EPOLLIN
- Set op to EPOLL_CTL_MOD
- Else:
- Set the events to EPOLLOUT
-
- Else:
- There is no read or write change; set op to 0 and events to 0.
-
- The logic is a little tricky, since we had no events set on the fd before,
- we need to set op="ADD" and set events=the events we want to add. If we
- had any events set on the fd before, and we want any events to remain on
- the fd, we need to say op="MOD" and set events=the events we want to
- remain. But if we want to delete the last event, we say op="DEL" and
- set events=(any non-null pointer).
-
- [*0] Actually, the Python script has gotten a bit more complicated, to
- support EPOLLRDHUP.
-
- [*1] This MOD is only a guess. MOD might fail with ENOENT if the file was
- closed and a new file was opened with the same fd. If so, we'll retry
- with ADD.
-
- [*2] We can't replace this with a no-op even if old_events is the same as
- the new events: if the file was closed and reopened, we need to retry
- with an ADD. (We do a MOD in this case since "no change" is more
- common than "close and reopen", so we'll usually wind up doing 1
- syscalls instead of 2.)
-
- [*3] This ADD is only a guess. There is a fun Linux kernel issue where if
- you have two fds for the same file (via dup) and you ADD one to an
- epfd, then close it, then re-create it with the same fd (via dup2 or an
- unlucky dup), then try to ADD it again, you'll get an EEXIST, since the
- struct epitem is not actually removed from the struct eventpoll until
- the file itself is closed.
-
- EV_CHANGE_ADD==1
- EV_CHANGE_DEL==2
- EV_READ ==2
- EV_WRITE ==4
- EV_CLOSED ==0x80
-
- Bit 0: close change is add
- Bit 1: close change is del
- Bit 2: read change is add
- Bit 3: read change is del
- Bit 4: write change is add
- Bit 5: write change is del
- Bit 6: old events had EV_READ
- Bit 7: old events had EV_WRITE
- Bit 8: old events had EV_CLOSED
-*/
-
-#define EPOLL_OP_TABLE_INDEX(c) \
- ( (((c)->close_change&(EV_CHANGE_ADD|EV_CHANGE_DEL))) | \
- (((c)->read_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 2) | \
- (((c)->write_change&(EV_CHANGE_ADD|EV_CHANGE_DEL)) << 4) | \
- (((c)->old_events&(EV_READ|EV_WRITE)) << 5) | \
- (((c)->old_events&(EV_CLOSED)) << 1) \
- )
-
-#if EV_READ != 2 || EV_WRITE != 4 || EV_CLOSED != 0x80 || EV_CHANGE_ADD != 1 || EV_CHANGE_DEL != 2
-#error "Libevent's internals changed! Regenerate the op_table in epolltable-internal.h"
-#endif
-
-static const struct operation {
- int events;
- int op;
-} epoll_op_table[] = {
- /* old= 0, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= 0, write: 0, read: 0, close:add */
- { EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write: 0, read: 0, close:del */
- { EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= 0, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= 0, write: 0, read:add, close: 0 */
- { EPOLLIN, EPOLL_CTL_ADD },
- /* old= 0, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write: 0, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_ADD },
- /* old= 0, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= 0, write: 0, read:del, close: 0 */
- { EPOLLIN, EPOLL_CTL_DEL },
- /* old= 0, write: 0, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write: 0, read:del, close:del */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= 0, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= 0, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= 0, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= 0, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= 0, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= 0, write:add, read: 0, close: 0 */
- { EPOLLOUT, EPOLL_CTL_ADD },
- /* old= 0, write:add, read: 0, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write:add, read: 0, close:del */
- { EPOLLOUT, EPOLL_CTL_ADD },
- /* old= 0, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= 0, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
- /* old= 0, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD },
- /* old= 0, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= 0, write:add, read:del, close: 0 */
- { EPOLLOUT, EPOLL_CTL_ADD },
- /* old= 0, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_ADD },
- /* old= 0, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= 0, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= 0, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= 0, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= 0, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= 0, write:del, read: 0, close: 0 */
- { EPOLLOUT, EPOLL_CTL_DEL },
- /* old= 0, write:del, read: 0, close:add */
- { EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write:del, read: 0, close:del */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= 0, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= 0, write:del, read:add, close: 0 */
- { EPOLLIN, EPOLL_CTL_ADD },
- /* old= 0, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_ADD },
- /* old= 0, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= 0, write:del, read:del, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
- /* old= 0, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_ADD },
- /* old= 0, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= 0, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= 0, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= 0, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= 0, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= 0, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= 0, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= 0, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= 0, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= 0, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= 0, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= 0, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= 0, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= 0, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= 0, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= 0, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= 0, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= 0, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= 0, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= 0, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= 0, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= 0, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old= r, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= r, write: 0, read: 0, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write: 0, read: 0, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= r, write: 0, read:add, close: 0 */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write: 0, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= r, write: 0, read:del, close: 0 */
- { EPOLLIN, EPOLL_CTL_DEL },
- /* old= r, write: 0, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write: 0, read:del, close:del */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= r, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= r, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= r, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= r, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= r, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= r, write:add, read: 0, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= r, write:add, read: 0, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write:add, read: 0, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= r, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= r, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= r, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= r, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= r, write:add, read:del, close: 0 */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= r, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= r, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= r, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= r, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= r, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= r, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= r, write:del, read: 0, close: 0 */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write:del, read: 0, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write:del, read: 0, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= r, write:del, read:add, close: 0 */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= r, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= r, write:del, read:del, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
- /* old= r, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= r, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= r, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= r, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= r, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= r, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= r, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= r, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= r, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= r, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= r, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= r, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= r, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= r, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= r, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= r, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= r, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= r, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= r, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= r, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= r, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= r, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= r, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old= w, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= w, write: 0, read: 0, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write: 0, read: 0, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= w, write: 0, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write: 0, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= w, write: 0, read:del, close: 0 */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write: 0, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write: 0, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= w, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= w, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= w, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= w, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= w, write:add, read: 0, close: 0 */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write:add, read: 0, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write:add, read: 0, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= w, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= w, write:add, read:del, close: 0 */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= w, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= w, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= w, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= w, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= w, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= w, write:del, read: 0, close: 0 */
- { EPOLLOUT, EPOLL_CTL_DEL },
- /* old= w, write:del, read: 0, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write:del, read: 0, close:del */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= w, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= w, write:del, read:add, close: 0 */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= w, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= w, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= w, write:del, read:del, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
- /* old= w, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= w, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= w, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= w, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= w, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= w, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= w, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= w, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= w, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= w, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= w, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= w, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= w, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= w, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= w, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= w, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= w, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= w, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= w, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= w, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= w, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= w, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= w, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old= rw, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= rw, write: 0, read: 0, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read: 0, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= rw, write: 0, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= rw, write: 0, read:del, close: 0 */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= rw, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= rw, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= rw, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= rw, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= rw, write:add, read: 0, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write:add, read: 0, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write:add, read: 0, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= rw, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= rw, write:add, read:del, close: 0 */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= rw, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= rw, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= rw, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= rw, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= rw, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= rw, write:del, read: 0, close: 0 */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= rw, write:del, read: 0, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write:del, read: 0, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= rw, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= rw, write:del, read:add, close: 0 */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= rw, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= rw, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= rw, write:del, read:del, close: 0 */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_DEL },
- /* old= rw, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= rw, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= rw, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= rw, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= rw, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= rw, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= rw, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= rw, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= rw, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= rw, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= rw, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= rw, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= rw, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= rw, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= rw, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= rw, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= rw, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= rw, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= rw, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= rw, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= rw, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= rw, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= rw, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old= c, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= c, write: 0, read: 0, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write: 0, read: 0, close:del */
- { EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= c, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= c, write: 0, read:add, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write: 0, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= c, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= c, write: 0, read:del, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write: 0, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write: 0, read:del, close:del */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= c, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= c, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= c, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= c, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= c, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= c, write:add, read: 0, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:add, read: 0, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:add, read: 0, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= c, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= c, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= c, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= c, write:add, read:del, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= c, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= c, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= c, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= c, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= c, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= c, write:del, read: 0, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:del, read: 0, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:del, read: 0, close:del */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= c, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= c, write:del, read:add, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= c, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= c, write:del, read:del, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= c, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= c, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= c, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= c, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= c, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= c, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= c, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= c, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= c, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= c, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= c, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= c, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= c, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= c, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= c, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= c, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= c, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= c, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= c, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= c, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= c, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= c, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cr, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= cr, write: 0, read: 0, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read: 0, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= cr, write: 0, read:add, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= cr, write: 0, read:del, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write: 0, read:del, close:del */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= cr, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= cr, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cr, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= cr, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= cr, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cr, write:add, read: 0, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:add, read: 0, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:add, read: 0, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cr, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= cr, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cr, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= cr, write:add, read:del, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cr, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= cr, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cr, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= cr, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= cr, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cr, write:del, read: 0, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:del, read: 0, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:del, read: 0, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= cr, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= cr, write:del, read:add, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= cr, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= cr, write:del, read:del, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cr, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= cr, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= cr, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cr, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= cr, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= cr, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cr, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= cr, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= cr, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= cr, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= cr, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= cr, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= cr, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= cr, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= cr, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= cr, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= cr, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= cr, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= cr, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cr, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= cr, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= cr, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cw, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old= cw, write: 0, read: 0, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read: 0, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old= cw, write: 0, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old= cw, write: 0, read:del, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cw, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old= cw, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cw, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old= cw, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old= cw, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cw, write:add, read: 0, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:add, read: 0, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:add, read: 0, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cw, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old= cw, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cw, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old= cw, write:add, read:del, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old= cw, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old= cw, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cw, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old= cw, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old= cw, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cw, write:del, read: 0, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:del, read: 0, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:del, read: 0, close:del */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= cw, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old= cw, write:del, read:add, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old= cw, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old= cw, write:del, read:del, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old= cw, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old= cw, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old= cw, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cw, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old= cw, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old= cw, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old= cw, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old= cw, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old= cw, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old= cw, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old= cw, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old= cw, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old= cw, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old= cw, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old= cw, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old= cw, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old= cw, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old= cw, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old= cw, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old= cw, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old= cw, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old= cw, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
- /* old=crw, write: 0, read: 0, close: 0 */
- { 0, 0 },
- /* old=crw, write: 0, read: 0, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read: 0, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read: 0, close:xxx */
- { 0, 255 },
- /* old=crw, write: 0, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read:add, close:xxx */
- { 0, 255 },
- /* old=crw, write: 0, read:del, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old=crw, write: 0, read:del, close:xxx */
- { 0, 255 },
- /* old=crw, write: 0, read:xxx, close: 0 */
- { 0, 255 },
- /* old=crw, write: 0, read:xxx, close:add */
- { 0, 255 },
- /* old=crw, write: 0, read:xxx, close:del */
- { 0, 255 },
- /* old=crw, write: 0, read:xxx, close:xxx */
- { 0, 255 },
- /* old=crw, write:add, read: 0, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:add, read: 0, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:add, read: 0, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old=crw, write:add, read: 0, close:xxx */
- { 0, 255 },
- /* old=crw, write:add, read:add, close: 0 */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:add, read:add, close:add */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:add, read:add, close:del */
- { EPOLLIN|EPOLLOUT, EPOLL_CTL_MOD },
- /* old=crw, write:add, read:add, close:xxx */
- { 0, 255 },
- /* old=crw, write:add, read:del, close: 0 */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:add, read:del, close:add */
- { EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:add, read:del, close:del */
- { EPOLLOUT, EPOLL_CTL_MOD },
- /* old=crw, write:add, read:del, close:xxx */
- { 0, 255 },
- /* old=crw, write:add, read:xxx, close: 0 */
- { 0, 255 },
- /* old=crw, write:add, read:xxx, close:add */
- { 0, 255 },
- /* old=crw, write:add, read:xxx, close:del */
- { 0, 255 },
- /* old=crw, write:add, read:xxx, close:xxx */
- { 0, 255 },
- /* old=crw, write:del, read: 0, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:del, read: 0, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:del, read: 0, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old=crw, write:del, read: 0, close:xxx */
- { 0, 255 },
- /* old=crw, write:del, read:add, close: 0 */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:del, read:add, close:add */
- { EPOLLIN|EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:del, read:add, close:del */
- { EPOLLIN, EPOLL_CTL_MOD },
- /* old=crw, write:del, read:add, close:xxx */
- { 0, 255 },
- /* old=crw, write:del, read:del, close: 0 */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:del, read:del, close:add */
- { EPOLLRDHUP, EPOLL_CTL_MOD },
- /* old=crw, write:del, read:del, close:del */
- { EPOLLIN|EPOLLOUT|EPOLLRDHUP, EPOLL_CTL_DEL },
- /* old=crw, write:del, read:del, close:xxx */
- { 0, 255 },
- /* old=crw, write:del, read:xxx, close: 0 */
- { 0, 255 },
- /* old=crw, write:del, read:xxx, close:add */
- { 0, 255 },
- /* old=crw, write:del, read:xxx, close:del */
- { 0, 255 },
- /* old=crw, write:del, read:xxx, close:xxx */
- { 0, 255 },
- /* old=crw, write:xxx, read: 0, close: 0 */
- { 0, 255 },
- /* old=crw, write:xxx, read: 0, close:add */
- { 0, 255 },
- /* old=crw, write:xxx, read: 0, close:del */
- { 0, 255 },
- /* old=crw, write:xxx, read: 0, close:xxx */
- { 0, 255 },
- /* old=crw, write:xxx, read:add, close: 0 */
- { 0, 255 },
- /* old=crw, write:xxx, read:add, close:add */
- { 0, 255 },
- /* old=crw, write:xxx, read:add, close:del */
- { 0, 255 },
- /* old=crw, write:xxx, read:add, close:xxx */
- { 0, 255 },
- /* old=crw, write:xxx, read:del, close: 0 */
- { 0, 255 },
- /* old=crw, write:xxx, read:del, close:add */
- { 0, 255 },
- /* old=crw, write:xxx, read:del, close:del */
- { 0, 255 },
- /* old=crw, write:xxx, read:del, close:xxx */
- { 0, 255 },
- /* old=crw, write:xxx, read:xxx, close: 0 */
- { 0, 255 },
- /* old=crw, write:xxx, read:xxx, close:add */
- { 0, 255 },
- /* old=crw, write:xxx, read:xxx, close:del */
- { 0, 255 },
- /* old=crw, write:xxx, read:xxx, close:xxx */
- { 0, 255 },
-};
-
-#endif
diff --git a/libs/libevent/src/evbuffer-internal.h b/libs/libevent/src/evbuffer-internal.h
deleted file mode 100644
index cf4bddc80e..0000000000
--- a/libs/libevent/src/evbuffer-internal.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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 EVBUFFER_INTERNAL_H_INCLUDED_
-#define EVBUFFER_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-#include "event2/util.h"
-#include "event2/event_struct.h"
-#include "util-internal.h"
-#include "defer-internal.h"
-
-/* Experimental cb flag: "never deferred." Implementation note:
- * these callbacks may get an inaccurate view of n_del/n_added in their
- * arguments. */
-#define EVBUFFER_CB_NODEFER 2
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-#include <sys/queue.h>
-
-/* Minimum allocation for a chain. We define this so that we're burning no
- * more than 5% of each allocation on overhead. It would be nice to lose even
- * less space, though. */
-#if EVENT__SIZEOF_VOID_P < 8
-#define MIN_BUFFER_SIZE 512
-#else
-#define MIN_BUFFER_SIZE 1024
-#endif
-
-/** A single evbuffer callback for an evbuffer. This function will be invoked
- * when bytes are added to or removed from the evbuffer. */
-struct evbuffer_cb_entry {
- /** Structures to implement a doubly-linked queue of callbacks */
- LIST_ENTRY(evbuffer_cb_entry) next;
- /** The callback function to invoke when this callback is called.
- If EVBUFFER_CB_OBSOLETE is set in flags, the cb_obsolete field is
- valid; otherwise, cb_func is valid. */
- union {
- evbuffer_cb_func cb_func;
- evbuffer_cb cb_obsolete;
- } cb;
- /** Argument to pass to cb. */
- void *cbarg;
- /** Currently set flags on this callback. */
- ev_uint32_t flags;
-};
-
-struct bufferevent;
-struct evbuffer_chain;
-struct evbuffer {
- /** The first chain in this buffer's linked list of chains. */
- struct evbuffer_chain *first;
- /** The last chain in this buffer's linked list of chains. */
- struct evbuffer_chain *last;
-
- /** Pointer to the next pointer pointing at the 'last_with_data' chain.
- *
- * To unpack:
- *
- * The last_with_data chain is the last chain that has any data in it.
- * If all chains in the buffer are empty, it is the first chain.
- * If the buffer has no chains, it is NULL.
- *
- * The last_with_datap pointer points at _whatever 'next' pointer_
- * points at the last_with_datap chain. If the last_with_data chain
- * is the first chain, or it is NULL, then the last_with_datap pointer
- * is &buf->first.
- */
- struct evbuffer_chain **last_with_datap;
-
- /** Total amount of bytes stored in all chains.*/
- size_t total_len;
-
- /** Number of bytes we have added to the buffer since we last tried to
- * invoke callbacks. */
- size_t n_add_for_cb;
- /** Number of bytes we have removed from the buffer since we last
- * tried to invoke callbacks. */
- size_t n_del_for_cb;
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- /** A lock used to mediate access to this buffer. */
- void *lock;
-#endif
- /** True iff we should free the lock field when we free this
- * evbuffer. */
- unsigned own_lock : 1;
- /** True iff we should not allow changes to the front of the buffer
- * (drains or prepends). */
- unsigned freeze_start : 1;
- /** True iff we should not allow changes to the end of the buffer
- * (appends) */
- unsigned freeze_end : 1;
- /** True iff this evbuffer's callbacks are not invoked immediately
- * upon a change in the buffer, but instead are deferred to be invoked
- * from the event_base's loop. Useful for preventing enormous stack
- * overflows when we have mutually recursive callbacks, and for
- * serializing callbacks in a single thread. */
- unsigned deferred_cbs : 1;
-#ifdef _WIN32
- /** True iff this buffer is set up for overlapped IO. */
- unsigned is_overlapped : 1;
-#endif
- /** Zero or more EVBUFFER_FLAG_* bits */
- ev_uint32_t flags;
-
- /** Used to implement deferred callbacks. */
- struct event_base *cb_queue;
-
- /** A reference count on this evbuffer. When the reference count
- * reaches 0, the buffer is destroyed. Manipulated with
- * evbuffer_incref and evbuffer_decref_and_unlock and
- * evbuffer_free. */
- int refcnt;
-
- /** A struct event_callback handle to make all of this buffer's callbacks
- * invoked from the event loop. */
- struct event_callback deferred;
-
- /** A doubly-linked-list of callback functions */
- LIST_HEAD(evbuffer_cb_queue, evbuffer_cb_entry) callbacks;
-
- /** The parent bufferevent object this evbuffer belongs to.
- * NULL if the evbuffer stands alone. */
- struct bufferevent *parent;
-};
-
-#if EVENT__SIZEOF_OFF_T < EVENT__SIZEOF_SIZE_T
-typedef ev_ssize_t ev_misalign_t;
-#define EVBUFFER_CHAIN_MAX ((size_t)EV_SSIZE_MAX)
-#else
-typedef ev_off_t ev_misalign_t;
-#if EVENT__SIZEOF_OFF_T > EVENT__SIZEOF_SIZE_T
-#define EVBUFFER_CHAIN_MAX EV_SIZE_MAX
-#else
-#define EVBUFFER_CHAIN_MAX ((size_t)EV_SSIZE_MAX)
-#endif
-#endif
-
-/** A single item in an evbuffer. */
-struct evbuffer_chain {
- /** points to next buffer in the chain */
- struct evbuffer_chain *next;
-
- /** total allocation available in the buffer field. */
- size_t buffer_len;
-
- /** unused space at the beginning of buffer or an offset into a
- * file for sendfile buffers. */
- ev_misalign_t misalign;
-
- /** Offset into buffer + misalign at which to start writing.
- * In other words, the total number of bytes actually stored
- * in buffer. */
- size_t off;
-
- /** Set if special handling is required for this chain */
- unsigned flags;
-#define EVBUFFER_FILESEGMENT 0x0001 /**< A chain used for a file segment */
-#define EVBUFFER_SENDFILE 0x0002 /**< a chain used with sendfile */
-#define EVBUFFER_REFERENCE 0x0004 /**< a chain with a mem reference */
-#define EVBUFFER_IMMUTABLE 0x0008 /**< read-only chain */
- /** a chain that mustn't be reallocated or freed, or have its contents
- * memmoved, until the chain is un-pinned. */
-#define EVBUFFER_MEM_PINNED_R 0x0010
-#define EVBUFFER_MEM_PINNED_W 0x0020
-#define EVBUFFER_MEM_PINNED_ANY (EVBUFFER_MEM_PINNED_R|EVBUFFER_MEM_PINNED_W)
- /** a chain that should be freed, but can't be freed until it is
- * un-pinned. */
-#define EVBUFFER_DANGLING 0x0040
- /** a chain that is a referenced copy of another chain */
-#define EVBUFFER_MULTICAST 0x0080
-
- /** number of references to this chain */
- int refcnt;
-
- /** Usually points to the read-write memory belonging to this
- * buffer allocated as part of the evbuffer_chain allocation.
- * For mmap, this can be a read-only buffer and
- * EVBUFFER_IMMUTABLE will be set in flags. For sendfile, it
- * may point to NULL.
- */
- unsigned char *buffer;
-};
-
-/** callback for a reference chain; lets us know what to do with it when
- * we're done with it. Lives at the end of an evbuffer_chain with the
- * EVBUFFER_REFERENCE flag set */
-struct evbuffer_chain_reference {
- evbuffer_ref_cleanup_cb cleanupfn;
- void *extra;
-};
-
-/** File segment for a file-segment chain. Lives at the end of an
- * evbuffer_chain with the EVBUFFER_FILESEGMENT flag set. */
-struct evbuffer_chain_file_segment {
- struct evbuffer_file_segment *segment;
-#ifdef _WIN32
- /** If we're using CreateFileMapping, this is the handle to the view. */
- HANDLE view_handle;
-#endif
-};
-
-/* Declared in event2/buffer.h; defined here. */
-struct evbuffer_file_segment {
- void *lock; /**< lock prevent concurrent access to refcnt */
- int refcnt; /**< Reference count for this file segment */
- unsigned flags; /**< combination of EVBUF_FS_* flags */
-
- /** What kind of file segment is this? */
- unsigned can_sendfile : 1;
- unsigned is_mapping : 1;
-
- /** The fd that we read the data from. */
- int fd;
- /** If we're using mmap, this is the raw mapped memory. */
- void *mapping;
-#ifdef _WIN32
- /** If we're using CreateFileMapping, this is the mapping */
- HANDLE mapping_handle;
-#endif
- /** If we're using mmap or IO, this is the content of the file
- * segment. */
- char *contents;
- /** Position of this segment within the file. */
- ev_off_t file_offset;
- /** If we're using mmap, this is the offset within 'mapping' where
- * this data segment begins. */
- ev_off_t mmap_offset;
- /** The length of this segment. */
- ev_off_t length;
- /** Cleanup callback function */
- evbuffer_file_segment_cleanup_cb cleanup_cb;
- /** Argument to be pass to cleanup callback function */
- void *cleanup_cb_arg;
-};
-
-/** Information about the multicast parent of a chain. Lives at the
- * end of an evbuffer_chain with the EVBUFFER_MULTICAST flag set. */
-struct evbuffer_multicast_parent {
- /** source buffer the multicast parent belongs to */
- struct evbuffer *source;
- /** multicast parent for this chain */
- struct evbuffer_chain *parent;
-};
-
-#define EVBUFFER_CHAIN_SIZE sizeof(struct evbuffer_chain)
-/** Return a pointer to extra data allocated along with an evbuffer. */
-#define EVBUFFER_CHAIN_EXTRA(t, c) (t *)((struct evbuffer_chain *)(c) + 1)
-
-/** Assert that we are holding the lock on an evbuffer */
-#define ASSERT_EVBUFFER_LOCKED(buffer) \
- EVLOCK_ASSERT_LOCKED((buffer)->lock)
-
-#define EVBUFFER_LOCK(buffer) \
- do { \
- EVLOCK_LOCK((buffer)->lock, 0); \
- } while (0)
-#define EVBUFFER_UNLOCK(buffer) \
- do { \
- EVLOCK_UNLOCK((buffer)->lock, 0); \
- } while (0)
-#define EVBUFFER_LOCK2(buffer1, buffer2) \
- do { \
- EVLOCK_LOCK2((buffer1)->lock, (buffer2)->lock, 0, 0); \
- } while (0)
-#define EVBUFFER_UNLOCK2(buffer1, buffer2) \
- do { \
- EVLOCK_UNLOCK2((buffer1)->lock, (buffer2)->lock, 0, 0); \
- } while (0)
-
-/** Increase the reference count of buf by one. */
-void evbuffer_incref_(struct evbuffer *buf);
-/** Increase the reference count of buf by one and acquire the lock. */
-void evbuffer_incref_and_lock_(struct evbuffer *buf);
-/** Pin a single buffer chain using a given flag. A pinned chunk may not be
- * moved or freed until it is unpinned. */
-void evbuffer_chain_pin_(struct evbuffer_chain *chain, unsigned flag);
-/** Unpin a single buffer chain using a given flag. */
-void evbuffer_chain_unpin_(struct evbuffer_chain *chain, unsigned flag);
-/** As evbuffer_free, but requires that we hold a lock on the buffer, and
- * releases the lock before freeing it and the buffer. */
-void evbuffer_decref_and_unlock_(struct evbuffer *buffer);
-
-/** As evbuffer_expand, but does not guarantee that the newly allocated memory
- * is contiguous. Instead, it may be split across two or more chunks. */
-int evbuffer_expand_fast_(struct evbuffer *, size_t, int);
-
-/** Helper: prepares for a readv/WSARecv call by expanding the buffer to
- * hold enough memory to read 'howmuch' bytes in possibly noncontiguous memory.
- * Sets up the one or two iovecs in 'vecs' to point to the free memory and its
- * extent, and *chainp to point to the first chain that we'll try to read into.
- * Returns the number of vecs used.
- */
-int evbuffer_read_setup_vecs_(struct evbuffer *buf, ev_ssize_t howmuch,
- struct evbuffer_iovec *vecs, int n_vecs, struct evbuffer_chain ***chainp,
- int exact);
-
-/* Helper macro: copies an evbuffer_iovec in ei to a win32 WSABUF in i. */
-#define WSABUF_FROM_EVBUFFER_IOV(i,ei) do { \
- (i)->buf = (ei)->iov_base; \
- (i)->len = (unsigned long)(ei)->iov_len; \
- } while (0)
-/* XXXX the cast above is safe for now, but not if we allow mmaps on win64.
- * See note in buffer_iocp's launch_write function */
-
-/** Set the parent bufferevent object for buf to bev */
-void evbuffer_set_parent_(struct evbuffer *buf, struct bufferevent *bev);
-
-void evbuffer_invoke_callbacks_(struct evbuffer *buf);
-
-
-int evbuffer_get_callbacks_(struct evbuffer *buffer,
- struct event_callback **cbs,
- int max_cbs);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* EVBUFFER_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/evdns.c b/libs/libevent/src/evdns.c
deleted file mode 100644
index f087962336..0000000000
--- a/libs/libevent/src/evdns.c
+++ /dev/null
@@ -1,4761 +0,0 @@
-/* Copyright 2006-2007 Niels Provos
- * Copyright 2007-2012 Nick Mathewson and Niels Provos
- *
- * 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.
- */
-
-/* Based on software by Adam Langly. Adam's original message:
- *
- * 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 "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifndef _FORTIFY_SOURCE
-#define _FORTIFY_SOURCE 3
-#endif
-
-#include <string.h>
-#include <fcntl.h>
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef EVENT__HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <limits.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <stdarg.h>
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#ifndef _WIN32_IE
-#define _WIN32_IE 0x400
-#endif
-#include <shlobj.h>
-#endif
-
-#include "event2/dns.h"
-#include "event2/dns_struct.h"
-#include "event2/dns_compat.h"
-#include "event2/util.h"
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "event2/thread.h"
-
-#include "defer-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "strlcpy-internal.h"
-#include "ipv6-internal.h"
-#include "util-internal.h"
-#include "evthread-internal.h"
-#ifdef _WIN32
-#include <ctype.h>
-#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 EVENT__HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-
-#define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG
-#define EVDNS_LOG_WARN EVENT_LOG_WARN
-#define EVDNS_LOG_MSG EVENT_LOG_MSG
-
-#ifndef HOST_NAME_MAX
-#define HOST_NAME_MAX 255
-#endif
-
-#include <stdio.h>
-
-#undef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-
-#define ASSERT_VALID_REQUEST(req) \
- EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req))
-
-#define u64 ev_uint64_t
-#define u32 ev_uint32_t
-#define u16 ev_uint16_t
-#define u8 ev_uint8_t
-
-/* maximum number of addresses from a single packet */
-/* that we bother recording */
-#define MAX_V4_ADDRS 32
-#define MAX_V6_ADDRS 32
-
-
-#define TYPE_A EVDNS_TYPE_A
-#define TYPE_CNAME 5
-#define TYPE_PTR EVDNS_TYPE_PTR
-#define TYPE_SOA EVDNS_TYPE_SOA
-#define TYPE_AAAA EVDNS_TYPE_AAAA
-
-#define CLASS_INET EVDNS_CLASS_INET
-
-/* Persistent handle. We keep this separate from 'struct request' since we
- * need some object to last for as long as an evdns_request is outstanding so
- * that it can be canceled, whereas a search request can lead to multiple
- * 'struct request' instances being created over its lifetime. */
-struct evdns_request {
- struct request *current_req;
- struct evdns_base *base;
-
- int pending_cb; /* Waiting for its callback to be invoked; not
- * owned by event base any more. */
-
- /* 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;
-};
-
-struct request {
- u8 *request; /* the dns packet data */
- u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
- unsigned int request_len;
- int reissue_count;
- int tx_count; /* the number of times that this packet has been sent */
- 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 */
-
- /* these objects are kept in a circular list */
- /* XXX We could turn this into a CIRCLEQ. */
- struct request *next, *prev;
-
- struct event timeout_event;
-
- u16 trans_id; /* the transaction id */
- unsigned request_appended :1; /* true if the request pointer is data which follows this struct */
- unsigned transmit_me :1; /* needs to be transmitted */
-
- /* XXXX This is a horrible hack. */
- char **put_cname_in_ptr; /* store the cname here if we get one. */
-
- struct evdns_base *base;
-
- struct evdns_request *handle;
-};
-
-struct reply {
- unsigned int type;
- unsigned int have_answer : 1;
- union {
- struct {
- u32 addrcount;
- u32 addresses[MAX_V4_ADDRS];
- } a;
- struct {
- u32 addrcount;
- struct in6_addr addresses[MAX_V6_ADDRS];
- } aaaa;
- struct {
- char name[HOST_NAME_MAX];
- } ptr;
- } data;
-};
-
-struct nameserver {
- evutil_socket_t socket; /* a connected UDP socket */
- struct sockaddr_storage address;
- ev_socklen_t addrlen;
- 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 */
- /* Outstanding probe request for this nameserver, if any */
- struct evdns_request *probe_request;
- 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 */
- struct evdns_base *base;
-
- /* Number of currently inflight requests: used
- * to track when we should add/del the event. */
- int requests_inflight;
-};
-
-
-/* Represents a local port where we're listening for DNS requests. Right now, */
-/* only UDP is supported. */
-struct evdns_server_port {
- evutil_socket_t 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;
- struct event_base *event_base;
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- void *lock;
-#endif
-};
-
-/* 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; /* The RR type */
- u16 class; /* 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 */
- ev_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;
-};
-
-struct evdns_base {
- /* An array of n_req_heads circular lists for inflight requests.
- * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
- */
- struct request **req_heads;
- /* A circular list of requests that we're waiting to send, but haven't
- * sent yet because there are too many requests inflight */
- struct request *req_waiting_head;
- /* A circular list of nameservers. */
- struct nameserver *server_head;
- int n_req_heads;
-
- struct event_base *event_base;
-
- /* The number of good nameservers that we have */
- int global_good_nameservers;
-
- /* inflight requests are contained in the req_head list */
- /* and are actually going out across the network */
- int global_requests_inflight;
- /* requests which aren't inflight are in the waiting list */
- /* and are counted here */
- int global_requests_waiting;
-
- int global_max_requests_inflight;
-
- struct timeval global_timeout; /* 5 seconds by default */
- int global_max_reissues; /* a reissue occurs when we get some errors from the server */
- int global_max_retransmits; /* 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 */
- int global_max_nameserver_timeout;
- /* true iff we will use the 0x20 hack to prevent poisoning attacks. */
- int global_randomize_case;
-
- /* The first time that a nameserver fails, how long do we wait before
- * probing to see if it has returned? */
- struct timeval global_nameserver_probe_initial_timeout;
-
- /** Port to bind to for outgoing DNS packets. */
- struct sockaddr_storage global_outgoing_address;
- /** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */
- ev_socklen_t global_outgoing_addrlen;
-
- struct timeval global_getaddrinfo_allow_skew;
-
- int getaddrinfo_ipv4_timeouts;
- int getaddrinfo_ipv6_timeouts;
- int getaddrinfo_ipv4_answered;
- int getaddrinfo_ipv6_answered;
-
- struct search_state *global_search_state;
-
- TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- void *lock;
-#endif
-
- int disable_when_inactive;
-};
-
-struct hosts_entry {
- TAILQ_ENTRY(hosts_entry) next;
- union {
- struct sockaddr sa;
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- } addr;
- int addrlen;
- char hostname[1];
-};
-
-static struct evdns_base *current_base = NULL;
-
-struct evdns_base *
-evdns_get_global_base(void)
-{
- return current_base;
-}
-
-/* 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) - evutil_offsetof(struct server_request, base))))
-
-#define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
-
-static struct nameserver *nameserver_pick(struct evdns_base *base);
-static void evdns_request_insert(struct request *req, struct request **head);
-static void evdns_request_remove(struct request *req, struct request **head);
-static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
-static int evdns_transmit(struct evdns_base *base);
-static int evdns_request_transmit(struct request *req);
-static void nameserver_send_probe(struct nameserver *const ns);
-static void search_request_finished(struct evdns_request *const);
-static int search_try_next(struct evdns_request *const req);
-static struct request *search_request_new(struct evdns_base *base, struct evdns_request *handle, int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
-static void evdns_requests_pump_waiting_queue(struct evdns_base *base);
-static u16 transaction_id_pick(struct evdns_base *base);
-static struct request *request_new(struct evdns_base *base, struct evdns_request *handle, 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(evutil_socket_t fd, short events, void *arg);
-static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
-static int evdns_base_set_option_impl(struct evdns_base *base,
- const char *option, const char *val, int flags);
-static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
-static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg);
-
-static int strtoint(const char *const str);
-
-#ifdef EVENT__DISABLE_THREAD_SUPPORT
-#define EVDNS_LOCK(base) EVUTIL_NIL_STMT_
-#define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_
-#define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_
-#else
-#define EVDNS_LOCK(base) \
- EVLOCK_LOCK((base)->lock, 0)
-#define EVDNS_UNLOCK(base) \
- EVLOCK_UNLOCK((base)->lock, 0)
-#define ASSERT_LOCKED(base) \
- EVLOCK_ASSERT_LOCKED((base)->lock)
-#endif
-
-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 severity, const char *fmt, ...) EVDNS_LOG_CHECK;
-static void
-evdns_log_(int severity, const char *fmt, ...)
-{
- va_list args;
- va_start(args,fmt);
- if (evdns_log_fn) {
- char buf[512];
- int is_warn = (severity == EVDNS_LOG_WARN);
- evutil_vsnprintf(buf, sizeof(buf), fmt, args);
- evdns_log_fn(is_warn, buf);
- } else {
- event_logv_(severity, NULL, fmt, args);
- }
- 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(struct evdns_base *base, u16 trans_id) {
- struct request *req = REQ_HEAD(base, trans_id);
- struct request *const started_at = req;
-
- ASSERT_LOCKED(base);
-
- 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(evutil_socket_t fd, short events, void *arg) {
- struct nameserver *const ns = (struct nameserver *) arg;
- (void)fd;
- (void)events;
-
- EVDNS_LOCK(ns->base);
- nameserver_send_probe(ns);
- EVDNS_UNLOCK(ns->base);
-}
-
-/* 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) {
- struct timeval timeout;
- int i;
-
- ASSERT_LOCKED(ns->base);
- (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;
- }
-
-#define MAX_PROBE_TIMEOUT 3600
-#define TIMEOUT_BACKOFF_FACTOR 3
-
- memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
- sizeof(struct timeval));
- for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
- timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
- timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
- if (timeout.tv_usec > 1000000) {
- timeout.tv_sec += timeout.tv_usec / 1000000;
- timeout.tv_usec %= 1000000;
- }
- }
- if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
- timeout.tv_sec = MAX_PROBE_TIMEOUT;
- timeout.tv_usec = 0;
- }
-
- ns->failed_times++;
-
- if (evtimer_add(&ns->timeout_event, &timeout) < 0) {
- char addrbuf[128];
- log(EVDNS_LOG_WARN,
- "Error from libevent when adding timer event for %s",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ns->address,
- addrbuf, sizeof(addrbuf)));
- }
-}
-
-static void
-request_swap_ns(struct request *req, struct nameserver *ns) {
- if (ns && req->ns != ns) {
- EVUTIL_ASSERT(req->ns->requests_inflight > 0);
- req->ns->requests_inflight--;
- ns->requests_inflight++;
-
- req->ns = ns;
- }
-}
-
-/* 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;
- struct evdns_base *base = ns->base;
- int i;
- char addrbuf[128];
-
- ASSERT_LOCKED(base);
- /* if this nameserver has already been marked as failed */
- /* then don't do anything */
- if (!ns->state) return;
-
- log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ns->address,
- addrbuf, sizeof(addrbuf)),
- msg);
-
- base->global_good_nameservers--;
- EVUTIL_ASSERT(base->global_good_nameservers >= 0);
- if (base->global_good_nameservers == 0) {
- log(EVDNS_LOG_MSG, "All nameservers have failed");
- }
-
- ns->state = 0;
- ns->failed_times = 1;
-
- if (evtimer_add(&ns->timeout_event,
- &base->global_nameserver_probe_initial_timeout) < 0) {
- log(EVDNS_LOG_WARN,
- "Error from libevent when adding timer event for %s",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ns->address,
- addrbuf, sizeof(addrbuf)));
- /* ???? 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 (!base->global_good_nameservers) return;
-
- for (i = 0; i < base->n_req_heads; ++i) {
- req = started_at = base->req_heads[i];
- if (req) {
- do {
- if (req->tx_count == 0 && req->ns == ns) {
- /* still waiting to go out, can be moved */
- /* to another server */
- request_swap_ns(req, nameserver_pick(base));
- }
- req = req->next;
- } while (req != started_at);
- }
- }
-}
-
-static void
-nameserver_up(struct nameserver *const ns)
-{
- char addrbuf[128];
- ASSERT_LOCKED(ns->base);
- if (ns->state) return;
- log(EVDNS_LOG_MSG, "Nameserver %s is back up",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ns->address,
- addrbuf, sizeof(addrbuf)));
- evtimer_del(&ns->timeout_event);
- if (ns->probe_request) {
- evdns_cancel_request(ns->base, ns->probe_request);
- ns->probe_request = NULL;
- }
- ns->state = 1;
- ns->failed_times = 0;
- ns->timedout = 0;
- ns->base->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. */
-/* when free_handle is one, free the handle as well. */
-static void
-request_finished(struct request *const req, struct request **head, int free_handle) {
- struct evdns_base *base = req->base;
- int was_inflight = (head != &base->req_waiting_head);
- EVDNS_LOCK(base);
- ASSERT_VALID_REQUEST(req);
-
- if (head)
- evdns_request_remove(req, head);
-
- log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req);
- if (was_inflight) {
- evtimer_del(&req->timeout_event);
- base->global_requests_inflight--;
- req->ns->requests_inflight--;
- } else {
- base->global_requests_waiting--;
- }
- /* it was initialized during request_new / evtimer_assign */
- event_debug_unassign(&req->timeout_event);
-
- if (req->ns &&
- req->ns->requests_inflight == 0 &&
- req->base->disable_when_inactive) {
- event_del(&req->ns->event);
- evtimer_del(&req->ns->timeout_event);
- }
-
- if (!req->request_appended) {
- /* need to free the request data on it's own */
- mm_free(req->request);
- } else {
- /* the request data is appended onto the header */
- /* so everything gets free()ed when we: */
- }
-
- if (req->handle) {
- EVUTIL_ASSERT(req->handle->current_req == req);
-
- if (free_handle) {
- search_request_finished(req->handle);
- req->handle->current_req = NULL;
- if (! req->handle->pending_cb) {
- /* If we're planning to run the callback,
- * don't free the handle until later. */
- mm_free(req->handle);
- }
- req->handle = NULL; /* If we have a bug, let's crash
- * early */
- } else {
- req->handle->current_req = NULL;
- }
- }
-
- mm_free(req);
-
- evdns_requests_pump_waiting_queue(base);
- EVDNS_UNLOCK(base);
-}
-
-/* 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;
- ASSERT_LOCKED(req->base);
- ASSERT_VALID_REQUEST(req);
- /* the last nameserver should have been marked as failing */
- /* by the caller of this function, therefore pick will try */
- /* not to return it */
- request_swap_ns(req, nameserver_pick(req->base));
- 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. */
-/* */
-/* TODO: */
-/* add return code, see at nameserver_pick() and other functions. */
-static void
-evdns_requests_pump_waiting_queue(struct evdns_base *base) {
- ASSERT_LOCKED(base);
- while (base->global_requests_inflight < base->global_max_requests_inflight &&
- base->global_requests_waiting) {
- struct request *req;
-
- EVUTIL_ASSERT(base->req_waiting_head);
- req = base->req_waiting_head;
-
- req->ns = nameserver_pick(base);
- if (!req->ns)
- return;
-
- /* move a request from the waiting queue to the inflight queue */
- req->ns->requests_inflight++;
-
- evdns_request_remove(req, &base->req_waiting_head);
-
- base->global_requests_waiting--;
- base->global_requests_inflight++;
-
- request_trans_id_set(req, transaction_id_pick(base));
-
- evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
- evdns_request_transmit(req);
- evdns_transmit(base);
- }
-}
-
-/* TODO(nickm) document */
-struct deferred_reply_callback {
- struct event_callback deferred;
- struct evdns_request *handle;
- u8 request_type;
- u8 have_reply;
- u32 ttl;
- u32 err;
- evdns_callback_type user_callback;
- struct reply reply;
-};
-
-static void
-reply_run_callback(struct event_callback *d, void *user_pointer)
-{
- struct deferred_reply_callback *cb =
- EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred);
-
- switch (cb->request_type) {
- case TYPE_A:
- if (cb->have_reply)
- cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
- cb->reply.data.a.addrcount, cb->ttl,
- cb->reply.data.a.addresses,
- user_pointer);
- else
- cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
- break;
- case TYPE_PTR:
- if (cb->have_reply) {
- char *name = cb->reply.data.ptr.name;
- cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl,
- &name, user_pointer);
- } else {
- cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
- }
- break;
- case TYPE_AAAA:
- if (cb->have_reply)
- cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
- cb->reply.data.aaaa.addrcount, cb->ttl,
- cb->reply.data.aaaa.addresses,
- user_pointer);
- else
- cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
- break;
- default:
- EVUTIL_ASSERT(0);
- }
-
- if (cb->handle && cb->handle->pending_cb) {
- mm_free(cb->handle);
- }
-
- mm_free(cb);
-}
-
-static void
-reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
-{
- struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
-
- if (!d) {
- event_warn("%s: Couldn't allocate space for deferred callback.",
- __func__);
- return;
- }
-
- ASSERT_LOCKED(req->base);
-
- d->request_type = req->request_type;
- d->user_callback = req->user_callback;
- d->ttl = ttl;
- d->err = err;
- if (reply) {
- d->have_reply = 1;
- memcpy(&d->reply, reply, sizeof(struct reply));
- }
-
- if (req->handle) {
- req->handle->pending_cb = 1;
- d->handle = req->handle;
- }
-
- event_deferred_cb_init_(
- &d->deferred,
- event_get_priority(&req->timeout_event),
- reply_run_callback,
- req->user_pointer);
- event_deferred_cb_schedule_(
- req->base->event_base,
- &d->deferred);
-}
-
-/* this processes a parsed reply packet */
-static void
-reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
- int error;
- char addrbuf[128];
- static const int error_codes[] = {
- DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
- DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
- };
-
- ASSERT_LOCKED(req->base);
- ASSERT_VALID_REQUEST(req);
-
- if (flags & 0x020f || !reply || !reply->have_answer) {
- /* there was an error */
- if (flags & 0x0200) {
- error = DNS_ERR_TRUNCATED;
- } else if (flags & 0x000f) {
- u16 error_code = (flags & 0x000f) - 1;
- if (error_code > 4) {
- error = DNS_ERR_UNKNOWN;
- } else {
- error = error_codes[error_code];
- }
- } else if (reply && !reply->have_answer) {
- error = DNS_ERR_NODATA;
- } else {
- error = DNS_ERR_UNKNOWN;
- }
-
- switch (error) {
- case DNS_ERR_NOTIMPL:
- case DNS_ERR_REFUSED:
- /* we regard these errors as marking a bad nameserver */
- if (req->reissue_count < req->base->global_max_reissues) {
- char msg[64];
- evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)",
- error, evdns_err_to_string(error));
- nameserver_failed(req->ns, msg);
- if (!request_reissue(req)) return;
- }
- break;
- case DNS_ERR_SERVERFAILED:
- /* rcode 2 (servfailed) sometimes means "we
- * are broken" and sometimes (with some binds)
- * means "that request was very confusing."
- * Treat this as a timeout, not a failure.
- */
- log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver"
- "at %s; will allow the request to time out.",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&req->ns->address,
- addrbuf, sizeof(addrbuf)));
- /* Call the timeout function */
- evdns_request_timeout_callback(0, 0, req);
- return;
- default:
- /* we got a good reply from the nameserver: it is up. */
- if (req->handle == req->ns->probe_request) {
- /* Avoid double-free */
- req->ns->probe_request = NULL;
- }
-
- nameserver_up(req->ns);
- }
-
- if (req->handle->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->handle)) {
- /* 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. */
- return;
- }
- }
-
- /* all else failed. Pass the failure up */
- reply_schedule_callback(req, ttl, error, NULL);
- request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
- } else {
- /* all ok, tell the user */
- reply_schedule_callback(req, ttl, 0, reply);
- if (req->handle == req->ns->probe_request)
- req->ns->probe_request = NULL; /* Avoid double-free */
- nameserver_up(req->ns);
- request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
- }
-}
-
-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;
- 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;
- if (j + label_len > length) 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(struct evdns_base *base, u8 *packet, int length) {
- int j = 0, k = 0; /* index into packet */
- u16 t_; /* used by the macros */
- u32 t32_; /* used by the macros */
- char tmp_name[256], cmp_name[256]; /* used by the macros */
- int name_matches = 0;
-
- 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;
-
- ASSERT_LOCKED(base);
-
- 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(base, trans_id);
- if (!req) return -1;
- EVUTIL_ASSERT(req->base == base);
-
- 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) && (flags & 0x020f) != DNS_ERR_NOTEXIST) {
- /* there was an error and it's not NXDOMAIN */
- 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>
- */
- tmp_name[0] = '\0';
- cmp_name[0] = '\0';
- k = j;
- if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name)) < 0)
- goto err;
- if (name_parse(req->request, req->request_len, &k,
- cmp_name, sizeof(cmp_name))<0)
- goto err;
- if (!base->global_randomize_case) {
- if (strcmp(tmp_name, cmp_name) == 0)
- name_matches = 1;
- } else {
- if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0)
- name_matches = 1;
- }
-
- j += 4;
- if (j > length)
- goto err;
- }
-
- if (!name_matches)
- 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_V4_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_V4_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_CNAME) {
- char cname[HOST_NAME_MAX];
- if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
- j += datalength; continue;
- }
- if (name_parse(packet, length, &j, cname,
- sizeof(cname))<0)
- goto err;
- *req->put_cname_in_ptr = mm_strdup(cname);
- } 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_V6_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_V6_ADDRS) break;
- } else {
- /* skip over any other type of resource */
- j += datalength;
- }
- }
-
- if (!reply.have_answer) {
- for (i = 0; i < authority; ++i) {
- u16 type, class;
- SKIP_NAME;
- GET16(type);
- GET16(class);
- GET32(ttl);
- GET16(datalength);
- if (type == TYPE_SOA && class == CLASS_INET) {
- u32 serial, refresh, retry, expire, minimum;
- SKIP_NAME;
- SKIP_NAME;
- GET32(serial);
- GET32(refresh);
- GET32(retry);
- GET32(expire);
- GET32(minimum);
- (void)expire;
- (void)retry;
- (void)refresh;
- (void)serial;
- ttl_r = MIN(ttl_r, ttl);
- ttl_r = MIN(ttl_r, minimum);
- } else {
- /* skip over any other type of resource */
- j += datalength;
- }
- }
- }
-
- if (ttl_r == 0xffffffff)
- ttl_r = 0;
-
- 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, ev_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;
-
- ASSERT_LOCKED(port);
-
- /* Get the header fields */
- GET16(trans_id);
- GET16(flags);
- GET16(questions);
- GET16(answers);
- GET16(authority);
- GET16(additional);
- (void)answers;
- (void)additional;
- (void)authority;
-
- if (flags & 0x8000) return -1; /* Must not be an answer. */
- flags &= 0x0110; /* Only RD and CD get preserved. */
-
- server_req = mm_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 = mm_calloc(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 = (int)strlen(tmp_name);
- q = mm_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)
- mm_free(server_req->base.questions[i]);
- mm_free(server_req->base.questions);
- }
- mm_free(server_req);
- }
- return -1;
-
-#undef SKIP_NAME
-#undef GET32
-#undef GET16
-#undef GET8
-}
-
-
-void
-evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
-{
-}
-
-void
-evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
-{
-}
-
-/* Try to choose a strong transaction id which isn't already in flight */
-static u16
-transaction_id_pick(struct evdns_base *base) {
- ASSERT_LOCKED(base);
- for (;;) {
- u16 trans_id;
- evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id));
-
- if (trans_id == 0xffff) continue;
- /* now check to see if that id is already inflight */
- if (request_find_from_trans_id(base, trans_id) == NULL)
- 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(struct evdns_base *base) {
- struct nameserver *started_at = base->server_head, *picked;
- ASSERT_LOCKED(base);
- if (!base->server_head) return NULL;
-
- /* if we don't have any good nameservers then there's no */
- /* point in trying to find one. */
- if (!base->global_good_nameservers) {
- base->server_head = base->server_head->next;
- return base->server_head;
- }
-
- /* remember that nameservers are in a circular list */
- for (;;) {
- if (base->server_head->state) {
- /* we think this server is currently good */
- picked = base->server_head;
- base->server_head = base->server_head->next;
- return picked;
- }
-
- base->server_head = base->server_head->next;
- if (base->server_head == started_at) {
- /* all the nameservers seem to be down */
- /* so we just return this one and hope for the */
- /* best */
- EVUTIL_ASSERT(base->global_good_nameservers == 0);
- picked = base->server_head;
- base->server_head = base->server_head->next;
- return picked;
- }
- }
-}
-
-/* this is called when a namesever socket is ready for reading */
-static void
-nameserver_read(struct nameserver *ns) {
- struct sockaddr_storage ss;
- ev_socklen_t addrlen = sizeof(ss);
- u8 packet[1500];
- char addrbuf[128];
- ASSERT_LOCKED(ns->base);
-
- for (;;) {
- const int r = recvfrom(ns->socket, (void*)packet,
- sizeof(packet), 0,
- (struct sockaddr*)&ss, &addrlen);
- if (r < 0) {
- int err = evutil_socket_geterror(ns->socket);
- if (EVUTIL_ERR_RW_RETRIABLE(err))
- return;
- nameserver_failed(ns,
- evutil_socket_error_to_string(err));
- return;
- }
- if (evutil_sockaddr_cmp((struct sockaddr*)&ss,
- (struct sockaddr*)&ns->address, 0)) {
- log(EVDNS_LOG_WARN, "Address mismatch on received "
- "DNS packet. Apparent source was %s",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ss,
- addrbuf, sizeof(addrbuf)));
- return;
- }
-
- ns->timedout = 0;
- reply_parse(ns->base, 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;
- ev_socklen_t addrlen;
- int r;
- ASSERT_LOCKED(s);
-
- for (;;) {
- addrlen = sizeof(struct sockaddr_storage);
- r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
- (struct sockaddr*) &addr, &addrlen);
- if (r < 0) {
- int err = evutil_socket_geterror(s->socket);
- if (EVUTIL_ERR_RW_RETRIABLE(err))
- return;
- log(EVDNS_LOG_WARN,
- "Error %s (%d) while reading request.",
- evutil_socket_error_to_string(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)
-{
- struct server_request *req = port->pending_replies;
- ASSERT_LOCKED(port);
- while (req) {
- int r = sendto(port->socket, req->response, (int)req->response_len, 0,
- (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
- if (r < 0) {
- int err = evutil_socket_geterror(port->socket);
- if (EVUTIL_ERR_RW_RETRIABLE(err))
- return;
- log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err);
- }
- if (server_request_free(req)) {
- /* we released the last reference to req->port. */
- return;
- } else {
- EVUTIL_ASSERT(req != port->pending_replies);
- req = port->pending_replies;
- }
- }
-
- /* We have no more pending requests; stop listening for 'writeable' events. */
- (void) event_del(&port->event);
- event_assign(&port->event, port->event_base,
- 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) {
- ASSERT_LOCKED(ns->base);
- if (ns->write_waiting == waiting) return;
-
- ns->write_waiting = waiting;
- (void) event_del(&ns->event);
- event_assign(&ns->event, ns->base->event_base,
- ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
- nameserver_ready_callback, ns);
- if (event_add(&ns->event, NULL) < 0) {
- char addrbuf[128];
- log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ns->address,
- addrbuf, sizeof(addrbuf)));
- /* ???? 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(evutil_socket_t fd, short events, void *arg) {
- struct nameserver *ns = (struct nameserver *) arg;
- (void)fd;
-
- EVDNS_LOCK(ns->base);
- if (events & EV_WRITE) {
- ns->choked = 0;
- if (!evdns_transmit(ns->base)) {
- nameserver_write_waiting(ns, 0);
- }
- }
- if (events & EV_READ) {
- nameserver_read(ns);
- }
- EVDNS_UNLOCK(ns->base);
-}
-
-/* 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(evutil_socket_t fd, short events, void *arg) {
- struct evdns_server_port *port = (struct evdns_server_port *) arg;
- (void) fd;
-
- EVDNS_LOCK(port);
- if (events & EV_WRITE) {
- port->choked = 0;
- server_port_flush(port);
- }
- if (events & EV_READ) {
- server_port_read(port);
- }
- EVDNS_UNLOCK(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)
- mm_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 = mm_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 size_t 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 size_t 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++] = (ev_uint8_t)label_len;
-
- memcpy(buf + j, start, label_len);
- j += (int) label_len;
- break;
- } else {
- /* append length of the label. */
- const size_t 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++] = (ev_uint8_t)label_len;
-
- memcpy(buf + j, start, label_len);
- j += (int) label_len;
- /* 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 size_t
-evdns_request_len(const size_t 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 size_t 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_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
-{
- struct evdns_server_port *port;
- if (flags)
- return NULL; /* flags not yet implemented */
- if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
- return NULL;
- memset(port, 0, sizeof(struct evdns_server_port));
-
-
- 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;
- port->event_base = base;
-
- event_assign(&port->event, port->event_base,
- port->socket, EV_READ | EV_PERSIST,
- server_port_ready_callback, port);
- if (event_add(&port->event, NULL) < 0) {
- mm_free(port);
- return NULL;
- }
- EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- return port;
-}
-
-struct evdns_server_port *
-evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
-{
- return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data);
-}
-
-/* exported function */
-void
-evdns_close_server_port(struct evdns_server_port *port)
-{
- EVDNS_LOCK(port);
- if (--port->refcnt == 0) {
- EVDNS_UNLOCK(port);
- server_port_free(port);
- } else {
- 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;
- int result = -1;
-
- EVDNS_LOCK(req->port);
- if (req->response) /* have we already answered? */
- goto done;
-
- 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:
- goto done;
- }
- while (*itemp) {
- itemp = &((*itemp)->next);
- }
- item = mm_malloc(sizeof(struct server_reply_item));
- if (!item)
- goto done;
- item->next = NULL;
- if (!(item->name = mm_strdup(name))) {
- mm_free(item);
- goto done;
- }
- 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 = mm_strdup(data))) {
- mm_free(item->name);
- mm_free(item);
- goto done;
- }
- item->datalen = (u16)-1;
- } else {
- if (!(item->data = mm_malloc(datalen))) {
- mm_free(item->name);
- mm_free(item);
- goto done;
- }
- item->datalen = datalen;
- memcpy(item->data, data, datalen);
- }
- }
-
- *itemp = item;
- ++(*countp);
- result = 0;
-done:
- EVDNS_UNLOCK(req->port);
- return result;
-}
-
-/* exported function */
-int
-evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const 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, const 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];
- if (in && inaddr_name)
- return -1;
- else if (!in && !inaddr_name)
- return -1;
- if (in) {
- a = ntohl(in->s_addr);
- evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
- (int)(u8)((a )&0xff),
- (int)(u8)((a>>8 )&0xff),
- (int)(u8)((a>>16)&0xff),
- (int)(u8)((a>>24)&0xff));
- inaddr_name = buf;
- }
- return evdns_server_request_add_reply(
- req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
- ttl, -1, 1, hostname);
-}
-
-/* exported function */
-int
-evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
-{
- return evdns_server_request_add_reply(
- req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
- ttl, -1, 1, cname);
-}
-
-/* exported function */
-void
-evdns_server_request_set_flags(struct evdns_server_request *exreq, int flags)
-{
- struct server_request *req = TO_SERVER_REQUEST(exreq);
- req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD);
- req->base.flags |= flags;
-}
-
-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[2] |= 0x02; /* set the truncated bit. */
- }
-
- req->response_len = j;
-
- if (!(req->response = mm_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 = -1;
-
- EVDNS_LOCK(port);
- if (!req->response) {
- if ((r = evdns_server_request_format_response(req, err))<0)
- goto done;
- }
-
- r = sendto(port->socket, req->response, (int)req->response_len, 0,
- (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
- if (r<0) {
- int sock_err = evutil_socket_geterror(port->socket);
- if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
- goto done;
-
- 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_assign(&port->event, port->event_base, 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");
- }
-
- }
-
- r = 1;
- goto done;
- }
- if (server_request_free(req)) {
- r = 0;
- goto done;
- }
-
- if (port->pending_replies)
- server_port_flush(port);
-
- r = 0;
-done:
- EVDNS_UNLOCK(port);
- return r;
-}
-
-/* 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;
- mm_free(victim->name);
- if (victim->data)
- mm_free(victim->data);
- mm_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, lock=0;
- if (req->base.questions) {
- for (i = 0; i < req->base.nquestions; ++i)
- mm_free(req->base.questions[i]);
- mm_free(req->base.questions);
- }
-
- if (req->port) {
- EVDNS_LOCK(req->port);
- lock=1;
- if (req->port->pending_replies == req) {
- if (req->next_pending && req->next_pending != req)
- req->port->pending_replies = req->next_pending;
- else
- req->port->pending_replies = NULL;
- }
- rc = --req->port->refcnt;
- }
-
- if (req->response) {
- mm_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) {
- EVDNS_UNLOCK(req->port); /* ????? nickm */
- server_port_free(req->port);
- mm_free(req);
- return (1);
- }
- if (lock)
- EVDNS_UNLOCK(req->port);
- mm_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)
-{
- EVUTIL_ASSERT(port);
- EVUTIL_ASSERT(!port->refcnt);
- EVUTIL_ASSERT(!port->pending_replies);
- if (port->socket > 0) {
- evutil_closesocket(port->socket);
- port->socket = -1;
- }
- (void) event_del(&port->event);
- event_debug_unassign(&port->event);
- EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- mm_free(port);
-}
-
-/* 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(evutil_socket_t fd, short events, void *arg) {
- struct request *const req = (struct request *) arg;
- struct evdns_base *base = req->base;
-
- (void) fd;
- (void) events;
-
- log(EVDNS_LOG_DEBUG, "Request %p timed out", arg);
- EVDNS_LOCK(base);
-
- if (req->tx_count >= req->base->global_max_retransmits) {
- struct nameserver *ns = req->ns;
- /* this request has failed */
- log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d",
- arg, req->tx_count);
- reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
-
- request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
- nameserver_failed(ns, "request timed out.");
- } else {
- /* retransmit it */
- log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d",
- arg, req->tx_count);
- (void) evtimer_del(&req->timeout_event);
- request_swap_ns(req, nameserver_pick(base));
- evdns_request_transmit(req);
-
- req->ns->timedout++;
- if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
- req->ns->timedout = 0;
- nameserver_failed(req->ns, "request timed out.");
- }
- }
-
- EVDNS_UNLOCK(base);
-}
-
-/* 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) {
- int r;
- ASSERT_LOCKED(req->base);
- ASSERT_VALID_REQUEST(req);
-
- if (server->requests_inflight == 1 &&
- req->base->disable_when_inactive &&
- event_add(&server->event, NULL) < 0) {
- return 1;
- }
-
- r = sendto(server->socket, (void*)req->request, req->request_len, 0,
- (struct sockaddr *)&server->address, server->addrlen);
- if (r < 0) {
- int err = evutil_socket_geterror(server->socket);
- if (EVUTIL_ERR_RW_RETRIABLE(err))
- return 1;
- nameserver_failed(req->ns, evutil_socket_error_to_string(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;
-
- ASSERT_LOCKED(req->base);
- ASSERT_VALID_REQUEST(req);
- /* if we fail to send this packet then this flag marks it */
- /* for evdns_transmit */
- req->transmit_me = 1;
- EVUTIL_ASSERT(req->trans_id != 0xffff);
-
- if (!req->ns)
- {
- /* unable to transmit request if no nameservers */
- return 1;
- }
-
- 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 to transmit the request entirely. */
- retcode = 1;
- /* fall through: we'll set a timeout, which will time out,
- * and make us retransmit the request anyway. */
- default:
- /* all ok */
- log(EVDNS_LOG_DEBUG,
- "Setting timeout for request %p, sent to nameserver %p", req, req->ns);
- if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) {
- log(EVDNS_LOG_WARN,
- "Error from libevent when adding timer for request %p",
- 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_CANCEL) {
- /* We canceled this request because the nameserver came up
- * for some other reason. Do not change our opinion about
- * the nameserver. */
- return;
- }
-
- EVDNS_LOCK(ns->base);
- ns->probe_request = NULL;
- if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
- /* this is a good reply */
- nameserver_up(ns);
- } else {
- nameserver_probe_failed(ns);
- }
- EVDNS_UNLOCK(ns->base);
-}
-
-static void
-nameserver_send_probe(struct nameserver *const ns) {
- struct evdns_request *handle;
- struct request *req;
- char addrbuf[128];
- /* here we need to send a probe to a given nameserver */
- /* in the hope that it is up now. */
-
- ASSERT_LOCKED(ns->base);
- log(EVDNS_LOG_DEBUG, "Sending probe to %s",
- evutil_format_sockaddr_port_(
- (struct sockaddr *)&ns->address,
- addrbuf, sizeof(addrbuf)));
- handle = mm_calloc(1, sizeof(*handle));
- if (!handle) return;
- req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
- if (!req) {
- mm_free(handle);
- return;
- }
- ns->probe_request = handle;
- /* we force this into the inflight queue no matter what */
- request_trans_id_set(req, transaction_id_pick(ns->base));
- req->ns = ns;
- request_submit(req);
-}
-
-/* returns: */
-/* 0 didn't try to transmit anything */
-/* 1 tried to transmit something */
-static int
-evdns_transmit(struct evdns_base *base) {
- char did_try_to_transmit = 0;
- int i;
-
- ASSERT_LOCKED(base);
- for (i = 0; i < base->n_req_heads; ++i) {
- if (base->req_heads[i]) {
- struct request *const started_at = base->req_heads[i], *req = started_at;
- /* 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_base_count_nameservers(struct evdns_base *base)
-{
- const struct nameserver *server;
- int n = 0;
-
- EVDNS_LOCK(base);
- server = base->server_head;
- if (!server)
- goto done;
- do {
- ++n;
- server = server->next;
- } while (server != base->server_head);
-done:
- EVDNS_UNLOCK(base);
- return n;
-}
-
-int
-evdns_count_nameservers(void)
-{
- return evdns_base_count_nameservers(current_base);
-}
-
-/* exported function */
-int
-evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
-{
- struct nameserver *server, *started_at;
- int i;
-
- EVDNS_LOCK(base);
- server = base->server_head;
- started_at = base->server_head;
- if (!server) {
- EVDNS_UNLOCK(base);
- 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->probe_request) {
- evdns_cancel_request(server->base, server->probe_request);
- server->probe_request = NULL;
- }
- if (server->socket >= 0)
- evutil_closesocket(server->socket);
- mm_free(server);
- if (next == started_at)
- break;
- server = next;
- }
- base->server_head = NULL;
- base->global_good_nameservers = 0;
-
- for (i = 0; i < base->n_req_heads; ++i) {
- struct request *req, *req_started_at;
- req = req_started_at = base->req_heads[i];
- 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;
-
- base->global_requests_waiting++;
- evdns_request_insert(req, &base->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.*/
- base->req_waiting_head = base->req_waiting_head->prev;
-
- if (next == req_started_at)
- break;
- req = next;
- }
- base->req_heads[i] = NULL;
- }
-
- base->global_requests_inflight = 0;
-
- EVDNS_UNLOCK(base);
- return 0;
-}
-
-int
-evdns_clear_nameservers_and_suspend(void)
-{
- return evdns_base_clear_nameservers_and_suspend(current_base);
-}
-
-
-/* exported function */
-int
-evdns_base_resume(struct evdns_base *base)
-{
- EVDNS_LOCK(base);
- evdns_requests_pump_waiting_queue(base);
- EVDNS_UNLOCK(base);
-
- return 0;
-}
-
-int
-evdns_resume(void)
-{
- return evdns_base_resume(current_base);
-}
-
-static int
-evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
- /* first check to see if we already have this nameserver */
-
- const struct nameserver *server = base->server_head, *const started_at = base->server_head;
- struct nameserver *ns;
- int err = 0;
- char addrbuf[128];
-
- ASSERT_LOCKED(base);
- if (server) {
- do {
- if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3;
- server = server->next;
- } while (server != started_at);
- }
- if (addrlen > (int)sizeof(ns->address)) {
- log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
- return 2;
- }
-
- ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
- if (!ns) return -1;
-
- memset(ns, 0, sizeof(struct nameserver));
- ns->base = base;
-
- evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns);
-
- ns->socket = evutil_socket_(address->sa_family,
- SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
- if (ns->socket < 0) { err = 1; goto out1; }
-
- if (base->global_outgoing_addrlen &&
- !evutil_sockaddr_is_loopback_(address)) {
- if (bind(ns->socket,
- (struct sockaddr*)&base->global_outgoing_address,
- base->global_outgoing_addrlen) < 0) {
- log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
- err = 2;
- goto out2;
- }
- }
-
- memcpy(&ns->address, address, addrlen);
- ns->addrlen = addrlen;
- ns->state = 1;
- event_assign(&ns->event, ns->base->event_base, ns->socket,
- EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
- if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) {
- err = 2;
- goto out2;
- }
-
- log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p",
- evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns);
-
- /* insert this nameserver into the list of them */
- if (!base->server_head) {
- ns->next = ns->prev = ns;
- base->server_head = ns;
- } else {
- ns->next = base->server_head->next;
- ns->prev = base->server_head;
- base->server_head->next = ns;
- ns->next->prev = ns;
- }
-
- base->global_good_nameservers++;
-
- return 0;
-
-out2:
- evutil_closesocket(ns->socket);
-out1:
- event_debug_unassign(&ns->event);
- mm_free(ns);
- log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
- evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err);
- return err;
-}
-
-/* exported function */
-int
-evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address)
-{
- struct sockaddr_in sin;
- int res;
- memset(&sin, 0, sizeof(sin));
- sin.sin_addr.s_addr = address;
- sin.sin_port = htons(53);
- sin.sin_family = AF_INET;
- EVDNS_LOCK(base);
- res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin));
- EVDNS_UNLOCK(base);
- return res;
-}
-
-int
-evdns_nameserver_add(unsigned long int address) {
- if (!current_base)
- current_base = evdns_base_new(NULL, 0);
- return evdns_base_nameserver_add(current_base, address);
-}
-
-static void
-sockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
-{
- if (sa->sa_family == AF_INET) {
- ((struct sockaddr_in *)sa)->sin_port = htons(port);
- } else if (sa->sa_family == AF_INET6) {
- ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
- }
-}
-
-static ev_uint16_t
-sockaddr_getport(struct sockaddr *sa)
-{
- if (sa->sa_family == AF_INET) {
- return ntohs(((struct sockaddr_in *)sa)->sin_port);
- } else if (sa->sa_family == AF_INET6) {
- return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
- } else {
- return 0;
- }
-}
-
-/* exported function */
-int
-evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
- struct sockaddr_storage ss;
- struct sockaddr *sa;
- int len = sizeof(ss);
- int res;
- if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
- &len)) {
- log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
- ip_as_string);
- return 4;
- }
- sa = (struct sockaddr *) &ss;
- if (sockaddr_getport(sa) == 0)
- sockaddr_setport(sa, 53);
-
- EVDNS_LOCK(base);
- res = evdns_nameserver_add_impl_(base, sa, len);
- EVDNS_UNLOCK(base);
- return res;
-}
-
-int
-evdns_nameserver_ip_add(const char *ip_as_string) {
- if (!current_base)
- current_base = evdns_base_new(NULL, 0);
- return evdns_base_nameserver_ip_add(current_base, ip_as_string);
-}
-
-int
-evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
- const struct sockaddr *sa, ev_socklen_t len, unsigned flags)
-{
- int res;
- EVUTIL_ASSERT(base);
- EVDNS_LOCK(base);
- res = evdns_nameserver_add_impl_(base, sa, len);
- EVDNS_UNLOCK(base);
- return res;
-}
-
-int
-evdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
- struct sockaddr *sa, ev_socklen_t len)
-{
- int result = -1;
- int i;
- struct nameserver *server;
- EVDNS_LOCK(base);
- server = base->server_head;
- for (i = 0; i < idx && server; ++i, server = server->next) {
- if (server->next == base->server_head)
- goto done;
- }
- if (! server)
- goto done;
-
- if (server->addrlen > len) {
- result = (int) server->addrlen;
- goto done;
- }
-
- memcpy(sa, &server->address, server->addrlen);
- result = (int) server->addrlen;
-done:
- EVDNS_UNLOCK(base);
- return result;
-}
-
-/* remove from the queue */
-static void
-evdns_request_remove(struct request *req, struct request **head)
-{
- ASSERT_LOCKED(req->base);
- ASSERT_VALID_REQUEST(req);
-
-#if 0
- {
- struct request *ptr;
- int found = 0;
- EVUTIL_ASSERT(*head != NULL);
-
- ptr = *head;
- do {
- if (ptr == req) {
- found = 1;
- break;
- }
- ptr = ptr->next;
- } while (ptr != *head);
- EVUTIL_ASSERT(found);
-
- EVUTIL_ASSERT(req->next);
- }
-#endif
-
- 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;
- }
- req->next = req->prev = NULL;
-}
-
-/* insert into the tail of the queue */
-static void
-evdns_request_insert(struct request *req, struct request **head) {
- ASSERT_LOCKED(req->base);
- ASSERT_VALID_REQUEST(req);
- 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(struct evdns_base *base, struct evdns_request *handle, int type,
- const char *name, int flags, evdns_callback_type callback,
- void *user_ptr) {
-
- const char issuing_now =
- (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
-
- const size_t name_len = strlen(name);
- const size_t request_max_len = evdns_request_len(name_len);
- const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
- /* the request data is alloced in a single block with the header */
- struct request *const req =
- mm_malloc(sizeof(struct request) + request_max_len);
- int rlen;
- char namebuf[256];
- (void) flags;
-
- ASSERT_LOCKED(base);
-
- if (!req) return NULL;
-
- if (name_len >= sizeof(namebuf)) {
- mm_free(req);
- return NULL;
- }
-
- memset(req, 0, sizeof(struct request));
- req->base = base;
-
- evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
-
- if (base->global_randomize_case) {
- unsigned i;
- char randbits[(sizeof(namebuf)+7)/8];
- strlcpy(namebuf, name, sizeof(namebuf));
- evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
- for (i = 0; i < name_len; ++i) {
- if (EVUTIL_ISALPHA_(namebuf[i])) {
- if ((randbits[i >> 3] & (1<<(i & 7))))
- namebuf[i] |= 0x20;
- else
- namebuf[i] &= ~0x20;
- }
- }
- name = namebuf;
- }
-
- /* 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(base) : NULL;
- req->next = req->prev = NULL;
- req->handle = handle;
- if (handle) {
- handle->current_req = req;
- handle->base = base;
- }
-
- return req;
-err1:
- mm_free(req);
- return NULL;
-}
-
-static void
-request_submit(struct request *const req) {
- struct evdns_base *base = req->base;
- ASSERT_LOCKED(base);
- ASSERT_VALID_REQUEST(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(base, req->trans_id));
-
- base->global_requests_inflight++;
- req->ns->requests_inflight++;
-
- evdns_request_transmit(req);
- } else {
- evdns_request_insert(req, &base->req_waiting_head);
- base->global_requests_waiting++;
- }
-}
-
-/* exported function */
-void
-evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
-{
- struct request *req;
-
- if (!handle->current_req)
- return;
-
- if (!base) {
- /* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */
- base = handle->base;
- if (!base)
- base = handle->current_req->base;
- }
-
- EVDNS_LOCK(base);
- if (handle->pending_cb) {
- EVDNS_UNLOCK(base);
- return;
- }
-
- req = handle->current_req;
- ASSERT_VALID_REQUEST(req);
-
- reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
- if (req->ns) {
- /* remove from inflight queue */
- request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
- } else {
- /* remove from global_waiting head */
- request_finished(req, &base->req_waiting_head, 1);
- }
- EVDNS_UNLOCK(base);
-}
-
-/* exported function */
-struct evdns_request *
-evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
- evdns_callback_type callback, void *ptr) {
- struct evdns_request *handle;
- struct request *req;
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
- handle = mm_calloc(1, sizeof(*handle));
- if (handle == NULL)
- return NULL;
- EVDNS_LOCK(base);
- if (flags & DNS_QUERY_NO_SEARCH) {
- req =
- request_new(base, handle, TYPE_A, name, flags,
- callback, ptr);
- if (req)
- request_submit(req);
- } else {
- search_request_new(base, handle, TYPE_A, name, flags,
- callback, ptr);
- }
- if (handle->current_req == NULL) {
- mm_free(handle);
- handle = NULL;
- }
- EVDNS_UNLOCK(base);
- return handle;
-}
-
-int evdns_resolve_ipv4(const char *name, int flags,
- evdns_callback_type callback, void *ptr)
-{
- return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr)
- ? 0 : -1;
-}
-
-
-/* exported function */
-struct evdns_request *
-evdns_base_resolve_ipv6(struct evdns_base *base,
- const char *name, int flags,
- evdns_callback_type callback, void *ptr)
-{
- struct evdns_request *handle;
- struct request *req;
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
- handle = mm_calloc(1, sizeof(*handle));
- if (handle == NULL)
- return NULL;
- EVDNS_LOCK(base);
- if (flags & DNS_QUERY_NO_SEARCH) {
- req = request_new(base, handle, TYPE_AAAA, name, flags,
- callback, ptr);
- if (req)
- request_submit(req);
- } else {
- search_request_new(base, handle, TYPE_AAAA, name, flags,
- callback, ptr);
- }
- if (handle->current_req == NULL) {
- mm_free(handle);
- handle = NULL;
- }
- EVDNS_UNLOCK(base);
- return handle;
-}
-
-int evdns_resolve_ipv6(const char *name, int flags,
- evdns_callback_type callback, void *ptr) {
- return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr)
- ? 0 : -1;
-}
-
-struct evdns_request *
-evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- char buf[32];
- struct evdns_request *handle;
- struct request *req;
- u32 a;
- EVUTIL_ASSERT(in);
- a = ntohl(in->s_addr);
- evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
- (int)(u8)((a )&0xff),
- (int)(u8)((a>>8 )&0xff),
- (int)(u8)((a>>16)&0xff),
- (int)(u8)((a>>24)&0xff));
- handle = mm_calloc(1, sizeof(*handle));
- if (handle == NULL)
- return NULL;
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
- EVDNS_LOCK(base);
- req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
- if (req)
- request_submit(req);
- if (handle->current_req == NULL) {
- mm_free(handle);
- handle = NULL;
- }
- EVDNS_UNLOCK(base);
- return (handle);
-}
-
-int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr)
- ? 0 : -1;
-}
-
-struct evdns_request *
-evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
- char buf[73];
- char *cp;
- struct evdns_request *handle;
- struct request *req;
- int i;
- EVUTIL_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++ = '.';
- }
- EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
- memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
- handle = mm_calloc(1, sizeof(*handle));
- if (handle == NULL)
- return NULL;
- log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
- EVDNS_LOCK(base);
- req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
- if (req)
- request_submit(req);
- if (handle->current_req == NULL) {
- mm_free(handle);
- handle = NULL;
- }
- EVDNS_UNLOCK(base);
- return (handle);
-}
-
-int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
- return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr)
- ? 0 : -1;
-}
-
-/* ================================================================= */
-/* 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 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;
- mm_free(dom);
- }
- mm_free(state);
- }
-}
-
-static struct search_state *
-search_state_new(void) {
- struct search_state *state = (struct search_state *) mm_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(struct evdns_base *base) {
- search_state_decref(base->global_search_state);
-
- base->global_search_state = search_state_new();
-}
-
-/* exported function */
-void
-evdns_base_search_clear(struct evdns_base *base)
-{
- EVDNS_LOCK(base);
- search_postfix_clear(base);
- EVDNS_UNLOCK(base);
-}
-
-void
-evdns_search_clear(void) {
- evdns_base_search_clear(current_base);
-}
-
-static void
-search_postfix_add(struct evdns_base *base, const char *domain) {
- size_t domain_len;
- struct search_domain *sdomain;
- while (domain[0] == '.') domain++;
- domain_len = strlen(domain);
-
- ASSERT_LOCKED(base);
- if (!base->global_search_state) base->global_search_state = search_state_new();
- if (!base->global_search_state) return;
- base->global_search_state->num_domains++;
-
- sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
- if (!sdomain) return;
- memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
- sdomain->next = base->global_search_state->head;
- sdomain->len = (int) domain_len;
-
- base->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(struct evdns_base *base) {
- struct search_domain *cur, *prev = NULL, *next;
- ASSERT_LOCKED(base);
- cur = base->global_search_state->head;
- while (cur) {
- next = cur->next;
- cur->next = prev;
- prev = cur;
- cur = next;
- }
-
- base->global_search_state->head = prev;
-}
-
-/* exported function */
-void
-evdns_base_search_add(struct evdns_base *base, const char *domain) {
- EVDNS_LOCK(base);
- search_postfix_add(base, domain);
- EVDNS_UNLOCK(base);
-}
-void
-evdns_search_add(const char *domain) {
- evdns_base_search_add(current_base, domain);
-}
-
-/* exported function */
-void
-evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
- EVDNS_LOCK(base);
- if (!base->global_search_state) base->global_search_state = search_state_new();
- if (base->global_search_state)
- base->global_search_state->ndots = ndots;
- EVDNS_UNLOCK(base);
-}
-void
-evdns_search_ndots_set(const int ndots) {
- evdns_base_search_ndots_set(current_base, ndots);
-}
-
-static void
-search_set_from_hostname(struct evdns_base *base) {
- char hostname[HOST_NAME_MAX + 1], *domainname;
-
- ASSERT_LOCKED(base);
- search_postfix_clear(base);
- if (gethostname(hostname, sizeof(hostname))) return;
- domainname = strchr(hostname, '.');
- if (!domainname) return;
- search_postfix_add(base, domainname);
-}
-
-/* warning: returns malloced string */
-static char *
-search_make_new(const struct search_state *const state, int n, const char *const base_name) {
- const size_t 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 *) mm_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 */
- EVUTIL_ASSERT(0);
- return NULL; /* unreachable; stops warnings in some compilers. */
-}
-
-static struct request *
-search_request_new(struct evdns_base *base, struct evdns_request *handle,
- int type, const char *const name, int flags,
- evdns_callback_type user_callback, void *user_arg) {
- ASSERT_LOCKED(base);
- EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
- EVUTIL_ASSERT(handle->current_req == NULL);
- if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
- base->global_search_state &&
- base->global_search_state->num_domains) {
- /* we have some domains to search */
- struct request *req;
- if (string_num_dots(name) >= base->global_search_state->ndots) {
- req = request_new(base, handle, type, name, flags, user_callback, user_arg);
- if (!req) return NULL;
- handle->search_index = -1;
- } else {
- char *const new_name = search_make_new(base->global_search_state, 0, name);
- if (!new_name) return NULL;
- req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
- mm_free(new_name);
- if (!req) return NULL;
- handle->search_index = 0;
- }
- EVUTIL_ASSERT(handle->search_origname == NULL);
- handle->search_origname = mm_strdup(name);
- if (handle->search_origname == NULL) {
- /* XXX Should we dealloc req? If yes, how? */
- if (req)
- mm_free(req);
- return NULL;
- }
- handle->search_state = base->global_search_state;
- handle->search_flags = flags;
- base->global_search_state->refcount++;
- request_submit(req);
- return req;
- } else {
- struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
- if (!req) return NULL;
- request_submit(req);
- return req;
- }
-}
-
-/* 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 evdns_request *const handle) {
- struct request *req = handle->current_req;
- struct evdns_base *base = req->base;
- struct request *newreq;
- ASSERT_LOCKED(base);
- if (handle->search_state) {
- /* it is part of a search */
- char *new_name;
- handle->search_index++;
- if (handle->search_index >= handle->search_state->num_domains) {
- /* no more postfixes to try, however we may need to try */
- /* this name without a postfix */
- if (string_num_dots(handle->search_origname) < handle->search_state->ndots) {
- /* yep, we need to try it raw */
- newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer);
- log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname);
- if (newreq) {
- search_request_finished(handle);
- goto submit_next;
- }
- }
- return 1;
- }
-
- new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname);
- if (!new_name) return 1;
- log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index);
- newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer);
- mm_free(new_name);
- if (!newreq) return 1;
- goto submit_next;
- }
- return 1;
-
-submit_next:
- request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
- handle->current_req = newreq;
- newreq->handle = handle;
- request_submit(newreq);
- return 0;
-}
-
-static void
-search_request_finished(struct evdns_request *const handle) {
- ASSERT_LOCKED(handle->current_req->base);
- if (handle->search_state) {
- search_state_decref(handle->search_state);
- handle->search_state = NULL;
- }
- if (handle->search_origname) {
- mm_free(handle->search_origname);
- handle->search_origname = NULL;
- }
-}
-
-/* ================================================================= */
-/* Parsing resolv.conf files */
-
-static void
-evdns_resolv_set_defaults(struct evdns_base *base, int flags) {
- /* if the file isn't found then we assume a local resolver */
- ASSERT_LOCKED(base);
- if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
- if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
-}
-
-#ifndef EVENT__HAVE_STRTOK_R
-static char *
-strtok_r(char *s, const char *delim, char **state) {
- char *cp, *start;
- start = cp = s ? s : *state;
- if (!cp)
- return NULL;
- while (*cp && !strchr(delim, *cp))
- ++cp;
- if (!*cp) {
- if (cp == start)
- return NULL;
- *state = NULL;
- return start;
- } else {
- *cp++ = '\0';
- *state = cp;
- return start;
- }
-}
-#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;
-}
-
-/* Parse a number of seconds into a timeval; return -1 on error. */
-static int
-evdns_strtotimeval(const char *const str, struct timeval *out)
-{
- double d;
- char *endptr;
- d = strtod(str, &endptr);
- if (*endptr) return -1;
- if (d < 0) return -1;
- out->tv_sec = (int) d;
- out->tv_usec = (int) ((d - (int) d)*1000000);
- if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */
- return -1;
- return 0;
-}
-
-/* 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;
-}
-
-static int
-evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
-{
- int old_n_heads = base->n_req_heads, n_heads;
- struct request **old_heads = base->req_heads, **new_heads, *req;
- int i;
-
- ASSERT_LOCKED(base);
- if (maxinflight < 1)
- maxinflight = 1;
- n_heads = (maxinflight+4) / 5;
- EVUTIL_ASSERT(n_heads > 0);
- new_heads = mm_calloc(n_heads, sizeof(struct request*));
- if (!new_heads)
- return (-1);
- if (old_heads) {
- for (i = 0; i < old_n_heads; ++i) {
- while (old_heads[i]) {
- req = old_heads[i];
- evdns_request_remove(req, &old_heads[i]);
- evdns_request_insert(req, &new_heads[req->trans_id % n_heads]);
- }
- }
- mm_free(old_heads);
- }
- base->req_heads = new_heads;
- base->n_req_heads = n_heads;
- base->global_max_requests_inflight = maxinflight;
- return (0);
-}
-
-/* exported function */
-int
-evdns_base_set_option(struct evdns_base *base,
- const char *option, const char *val)
-{
- int res;
- EVDNS_LOCK(base);
- res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
- EVDNS_UNLOCK(base);
- return res;
-}
-
-static inline int
-str_matches_option(const char *s1, const char *optionname)
-{
- /* Option names are given as "option:" We accept either 'option' in
- * s1, or 'option:randomjunk'. The latter form is to implement the
- * resolv.conf parser. */
- size_t optlen = strlen(optionname);
- size_t slen = strlen(s1);
- if (slen == optlen || slen == optlen - 1)
- return !strncmp(s1, optionname, slen);
- else if (slen > optlen)
- return !strncmp(s1, optionname, optlen);
- else
- return 0;
-}
-
-static int
-evdns_base_set_option_impl(struct evdns_base *base,
- const char *option, const char *val, int flags)
-{
- ASSERT_LOCKED(base);
- if (str_matches_option(option, "ndots:")) {
- 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 (!base->global_search_state) base->global_search_state = search_state_new();
- if (!base->global_search_state) return -1;
- base->global_search_state->ndots = ndots;
- } else if (str_matches_option(option, "timeout:")) {
- struct timeval tv;
- if (evdns_strtotimeval(val, &tv) == -1) return -1;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
- memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
- } else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
- struct timeval tv;
- if (evdns_strtotimeval(val, &tv) == -1) return -1;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
- val);
- memcpy(&base->global_getaddrinfo_allow_skew, &tv,
- sizeof(struct timeval));
- } else if (str_matches_option(option, "max-timeouts:")) {
- 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);
- base->global_max_nameserver_timeout = maxtimeout;
- } else if (str_matches_option(option, "max-inflight:")) {
- 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);
- evdns_base_set_max_requests_inflight(base, maxinflight);
- } else if (str_matches_option(option, "attempts:")) {
- 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);
- base->global_max_retransmits = retries;
- } else if (str_matches_option(option, "randomize-case:")) {
- int randcase = strtoint(val);
- if (!(flags & DNS_OPTION_MISC)) return 0;
- base->global_randomize_case = randcase;
- } else if (str_matches_option(option, "bind-to:")) {
- /* XXX This only applies to successive nameservers, not
- * to already-configured ones. We might want to fix that. */
- int len = sizeof(base->global_outgoing_address);
- if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
- if (evutil_parse_sockaddr_port(val,
- (struct sockaddr*)&base->global_outgoing_address, &len))
- return -1;
- base->global_outgoing_addrlen = len;
- } else if (str_matches_option(option, "initial-probe-timeout:")) {
- struct timeval tv;
- if (evdns_strtotimeval(val, &tv) == -1) return -1;
- if (tv.tv_sec > 3600)
- tv.tv_sec = 3600;
- if (!(flags & DNS_OPTION_MISC)) return 0;
- log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
- val);
- memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
- sizeof(tv));
- }
- return 0;
-}
-
-int
-evdns_set_option(const char *option, const char *val, int flags)
-{
- if (!current_base)
- current_base = evdns_base_new(NULL, 0);
- return evdns_base_set_option(current_base, option, val);
-}
-
-static void
-resolv_conf_parse_line(struct evdns_base *base, 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);
- ASSERT_LOCKED(base);
- if (!first_token) return;
-
- if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
- const char *const nameserver = NEXT_TOKEN;
-
- if (nameserver)
- evdns_base_nameserver_ip_add(base, nameserver);
- } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
- const char *const domain = NEXT_TOKEN;
- if (domain) {
- search_postfix_clear(base);
- search_postfix_add(base, domain);
- }
- } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
- const char *domain;
- search_postfix_clear(base);
-
- while ((domain = NEXT_TOKEN)) {
- search_postfix_add(base, domain);
- }
- search_reverse(base);
- } else if (!strcmp(first_token, "options")) {
- const char *option;
- while ((option = NEXT_TOKEN)) {
- const char *val = strchr(option, ':');
- evdns_base_set_option_impl(base, 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_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
- int res;
- EVDNS_LOCK(base);
- res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
- EVDNS_UNLOCK(base);
- return res;
-}
-
-static char *
-evdns_get_default_hosts_filename(void)
-{
-#ifdef _WIN32
- /* Windows is a little coy about where it puts its configuration
- * files. Sure, they're _usually_ in C:\windows\system32, but
- * there's no reason in principle they couldn't be in
- * W:\hoboken chicken emergency\
- */
- char path[MAX_PATH+1];
- static const char hostfile[] = "\\drivers\\etc\\hosts";
- char *path_out;
- size_t len_out;
-
- if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
- return NULL;
- len_out = strlen(path)+strlen(hostfile)+1;
- path_out = mm_malloc(len_out);
- evutil_snprintf(path_out, len_out, "%s%s", path, hostfile);
- return path_out;
-#else
- return mm_strdup("/etc/hosts");
-#endif
-}
-
-static int
-evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
- size_t n;
- char *resolv;
- char *start;
- int err = 0;
-
- log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
-
- if (flags & DNS_OPTION_HOSTSFILE) {
- char *fname = evdns_get_default_hosts_filename();
- evdns_base_load_hosts(base, fname);
- if (fname)
- mm_free(fname);
- }
-
- if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) {
- if (err == -1) {
- /* No file. */
- evdns_resolv_set_defaults(base, flags);
- return 1;
- } else {
- return 2;
- }
- }
-
- start = resolv;
- for (;;) {
- char *const newline = strchr(start, '\n');
- if (!newline) {
- resolv_conf_parse_line(base, start, flags);
- break;
- } else {
- *newline = 0;
- resolv_conf_parse_line(base, start, flags);
- start = newline + 1;
- }
- }
-
- if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) {
- /* no nameservers were configured. */
- evdns_base_nameserver_ip_add(base, "127.0.0.1");
- err = 6;
- }
- if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) {
- search_set_from_hostname(base);
- }
-
- mm_free(resolv);
- return err;
-}
-
-int
-evdns_resolv_conf_parse(int flags, const char *const filename) {
- if (!current_base)
- current_base = evdns_base_new(NULL, 0);
- return evdns_base_resolv_conf_parse(current_base, flags, filename);
-}
-
-
-#ifdef _WIN32
-/* Add multiple nameservers from a space-or-comma-separated list. */
-static int
-evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
- const char *addr;
- char *buf;
- int r;
- ASSERT_LOCKED(base);
- while (*ips) {
- while (isspace(*ips) || *ips == ',' || *ips == '\t')
- ++ips;
- addr = ips;
- while (isdigit(*ips) || *ips == '.' || *ips == ':' ||
- *ips=='[' || *ips==']')
- ++ips;
- buf = mm_malloc(ips-addr+1);
- if (!buf) return 4;
- memcpy(buf, addr, ips-addr);
- buf[ips-addr] = '\0';
- r = evdns_base_nameserver_ip_add(base, buf);
- mm_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(struct evdns_base *base)
-{
- /* 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;
-
- ASSERT_LOCKED(base);
- if (!(handle = evutil_load_windows_system_library_(
- TEXT("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 = mm_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) {
- mm_free(buf);
- buf = mm_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;
- }
- }
-
- EVUTIL_ASSERT(fixed);
- added_any = 0;
- ns = &(fixed->DnsServerList);
- while (ns) {
- r = evdns_nameserver_ip_add_line(base, 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;
- } else {
- ++added_any;
- log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
- }
-
- ns = ns->Next;
- }
-
- if (!added_any) {
- log(EVDNS_LOG_DEBUG, "No nameservers added.");
- if (status == 0)
- status = -1;
- } else {
- status = 0;
- }
-
- done:
- if (buf)
- mm_free(buf);
- if (handle)
- FreeLibrary(handle);
- return status;
-}
-
-static int
-config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const wchar_t *subkey)
-{
- char *buf;
- DWORD bufsz = 0, type = 0;
- int status = 0;
-
- ASSERT_LOCKED(base);
- if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
- != ERROR_MORE_DATA)
- return -1;
- if (!(buf = mm_malloc(bufsz)))
- return -1;
-
- if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
- == ERROR_SUCCESS && bufsz > 1) {
- status = evdns_nameserver_ip_add_line(base,buf);
- }
-
- mm_free(buf);
- return status;
-}
-
-#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
-#define WIN_NS_9X_KEY SERVICES_KEY TEXT("VxD\\MSTCP")
-#define WIN_NS_NT_KEY SERVICES_KEY TEXT("Tcpip\\Parameters")
-
-static int
-load_nameservers_from_registry(struct evdns_base *base)
-{
- int found = 0;
- int r;
-#define TRY(k, name) \
- if (!found && config_nameserver_from_reg_key(base,k,TEXT(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); \
- }
-
- ASSERT_LOCKED(base);
-
- 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, TEXT("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
-}
-
-int
-evdns_base_config_windows_nameservers(struct evdns_base *base)
-{
- int r;
- char *fname;
- if (base == NULL)
- base = current_base;
- if (base == NULL)
- return -1;
- EVDNS_LOCK(base);
- fname = evdns_get_default_hosts_filename();
- log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname);
- evdns_base_load_hosts(base, fname);
- if (fname)
- mm_free(fname);
-
- if (load_nameservers_with_getnetworkparams(base) == 0) {
- EVDNS_UNLOCK(base);
- return 0;
- }
- r = load_nameservers_from_registry(base);
-
- EVDNS_UNLOCK(base);
- return r;
-}
-
-int
-evdns_config_windows_nameservers(void)
-{
- if (!current_base) {
- current_base = evdns_base_new(NULL, 1);
- return current_base == NULL ? -1 : 0;
- } else {
- return evdns_base_config_windows_nameservers(current_base);
- }
-}
-#endif
-
-struct evdns_base *
-evdns_base_new(struct event_base *event_base, int flags)
-{
- struct evdns_base *base;
-
- if (evutil_secure_rng_init() < 0) {
- log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
- "DNS can't run.");
- return NULL;
- }
-
- /* Give the evutil library a hook into its evdns-enabled
- * functionality. We can't just call evdns_getaddrinfo directly or
- * else libevent-core will depend on libevent-extras. */
- evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo);
-
- base = mm_malloc(sizeof(struct evdns_base));
- if (base == NULL)
- return (NULL);
- memset(base, 0, sizeof(struct evdns_base));
- base->req_waiting_head = NULL;
-
- EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- EVDNS_LOCK(base);
-
- /* Set max requests inflight and allocate req_heads. */
- base->req_heads = NULL;
-
- evdns_base_set_max_requests_inflight(base, 64);
-
- base->server_head = NULL;
- base->event_base = event_base;
- base->global_good_nameservers = base->global_requests_inflight =
- base->global_requests_waiting = 0;
-
- base->global_timeout.tv_sec = 5;
- base->global_timeout.tv_usec = 0;
- base->global_max_reissues = 1;
- base->global_max_retransmits = 3;
- base->global_max_nameserver_timeout = 3;
- base->global_search_state = NULL;
- base->global_randomize_case = 1;
- base->global_getaddrinfo_allow_skew.tv_sec = 3;
- base->global_getaddrinfo_allow_skew.tv_usec = 0;
- base->global_nameserver_probe_initial_timeout.tv_sec = 10;
- base->global_nameserver_probe_initial_timeout.tv_usec = 0;
-
- TAILQ_INIT(&base->hostsdb);
-
-#define EVDNS_BASE_ALL_FLAGS (0x8001)
- if (flags & ~EVDNS_BASE_ALL_FLAGS) {
- flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
- log(EVDNS_LOG_WARN,
- "Unrecognized flag passed to evdns_base_new(). Assuming "
- "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS.");
- }
-#undef EVDNS_BASE_ALL_FLAGS
-
- if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
- int r;
-#ifdef _WIN32
- r = evdns_base_config_windows_nameservers(base);
-#else
- r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
-#endif
- if (r == -1) {
- evdns_base_free_and_unlock(base, 0);
- return NULL;
- }
- }
- if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) {
- base->disable_when_inactive = 1;
- }
-
- EVDNS_UNLOCK(base);
- return base;
-}
-
-int
-evdns_init(void)
-{
- struct evdns_base *base = evdns_base_new(NULL, 1);
- if (base) {
- current_base = base;
- return 0;
- } else {
- return -1;
- }
-}
-
-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";
- case DNS_ERR_CANCEL: return "dns request canceled";
- case DNS_ERR_NODATA: return "no records in the reply";
- default: return "[Unknown error code]";
- }
-}
-
-static void
-evdns_nameserver_free(struct nameserver *server)
-{
- if (server->socket >= 0)
- evutil_closesocket(server->socket);
- (void) event_del(&server->event);
- event_debug_unassign(&server->event);
- if (server->state == 0)
- (void) event_del(&server->timeout_event);
- if (server->probe_request) {
- evdns_cancel_request(server->base, server->probe_request);
- server->probe_request = NULL;
- }
- event_debug_unassign(&server->timeout_event);
- mm_free(server);
-}
-
-static void
-evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
-{
- struct nameserver *server, *server_next;
- struct search_domain *dom, *dom_next;
- int i;
-
- /* Requires that we hold the lock. */
-
- /* TODO(nickm) we might need to refcount here. */
-
- for (i = 0; i < base->n_req_heads; ++i) {
- while (base->req_heads[i]) {
- if (fail_requests)
- reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
- request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
- }
- }
- while (base->req_waiting_head) {
- if (fail_requests)
- reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
- request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
- }
- base->global_requests_inflight = base->global_requests_waiting = 0;
-
- for (server = base->server_head; server; server = server_next) {
- server_next = server->next;
- evdns_nameserver_free(server);
- if (server_next == base->server_head)
- break;
- }
- base->server_head = NULL;
- base->global_good_nameservers = 0;
-
- if (base->global_search_state) {
- for (dom = base->global_search_state->head; dom; dom = dom_next) {
- dom_next = dom->next;
- mm_free(dom);
- }
- mm_free(base->global_search_state);
- base->global_search_state = NULL;
- }
-
- {
- struct hosts_entry *victim;
- while ((victim = TAILQ_FIRST(&base->hostsdb))) {
- TAILQ_REMOVE(&base->hostsdb, victim, next);
- mm_free(victim);
- }
- }
-
- mm_free(base->req_heads);
-
- EVDNS_UNLOCK(base);
- EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
-
- mm_free(base);
-}
-
-void
-evdns_base_free(struct evdns_base *base, int fail_requests)
-{
- EVDNS_LOCK(base);
- evdns_base_free_and_unlock(base, fail_requests);
-}
-
-void
-evdns_base_clear_host_addresses(struct evdns_base *base)
-{
- struct hosts_entry *victim;
- EVDNS_LOCK(base);
- while ((victim = TAILQ_FIRST(&base->hostsdb))) {
- TAILQ_REMOVE(&base->hostsdb, victim, next);
- mm_free(victim);
- }
- EVDNS_UNLOCK(base);
-}
-
-void
-evdns_shutdown(int fail_requests)
-{
- if (current_base) {
- struct evdns_base *b = current_base;
- current_base = NULL;
- evdns_base_free(b, fail_requests);
- }
- evdns_log_fn = NULL;
-}
-
-static int
-evdns_base_parse_hosts_line(struct evdns_base *base, char *line)
-{
- char *strtok_state;
- static const char *const delims = " \t";
- char *const addr = strtok_r(line, delims, &strtok_state);
- char *hostname, *hash;
- struct sockaddr_storage ss;
- int socklen = sizeof(ss);
- ASSERT_LOCKED(base);
-
-#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
-
- if (!addr || *addr == '#')
- return 0;
-
- memset(&ss, 0, sizeof(ss));
- if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
- return -1;
- if (socklen > (int)sizeof(struct sockaddr_in6))
- return -1;
-
- if (sockaddr_getport((struct sockaddr*)&ss))
- return -1;
-
- while ((hostname = NEXT_TOKEN)) {
- struct hosts_entry *he;
- size_t namelen;
- if ((hash = strchr(hostname, '#'))) {
- if (hash == hostname)
- return 0;
- *hash = '\0';
- }
-
- namelen = strlen(hostname);
-
- he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
- if (!he)
- return -1;
- EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr));
- memcpy(&he->addr, &ss, socklen);
- memcpy(he->hostname, hostname, namelen+1);
- he->addrlen = socklen;
-
- TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
-
- if (hash)
- return 0;
- }
-
- return 0;
-#undef NEXT_TOKEN
-}
-
-static int
-evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
-{
- char *str=NULL, *cp, *eol;
- size_t len;
- int err=0;
-
- ASSERT_LOCKED(base);
-
- if (hosts_fname == NULL ||
- (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) {
- char tmp[64];
- strlcpy(tmp, "127.0.0.1 localhost", sizeof(tmp));
- evdns_base_parse_hosts_line(base, tmp);
- strlcpy(tmp, "::1 localhost", sizeof(tmp));
- evdns_base_parse_hosts_line(base, tmp);
- return err ? -1 : 0;
- }
-
- /* This will break early if there is a NUL in the hosts file.
- * Probably not a problem.*/
- cp = str;
- for (;;) {
- eol = strchr(cp, '\n');
-
- if (eol) {
- *eol = '\0';
- evdns_base_parse_hosts_line(base, cp);
- cp = eol+1;
- } else {
- evdns_base_parse_hosts_line(base, cp);
- break;
- }
- }
-
- mm_free(str);
- return 0;
-}
-
-int
-evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
-{
- int res;
- if (!base)
- base = current_base;
- EVDNS_LOCK(base);
- res = evdns_base_load_hosts_impl(base, hosts_fname);
- EVDNS_UNLOCK(base);
- return res;
-}
-
-/* A single request for a getaddrinfo, either v4 or v6. */
-struct getaddrinfo_subrequest {
- struct evdns_request *r;
- ev_uint32_t type;
-};
-
-/* State data used to implement an in-progress getaddrinfo. */
-struct evdns_getaddrinfo_request {
- struct evdns_base *evdns_base;
- /* Copy of the modified 'hints' data that we'll use to build
- * answers. */
- struct evutil_addrinfo hints;
- /* The callback to invoke when we're done */
- evdns_getaddrinfo_cb user_cb;
- /* User-supplied data to give to the callback. */
- void *user_data;
- /* The port to use when building sockaddrs. */
- ev_uint16_t port;
- /* The sub_request for an A record (if any) */
- struct getaddrinfo_subrequest ipv4_request;
- /* The sub_request for an AAAA record (if any) */
- struct getaddrinfo_subrequest ipv6_request;
-
- /* The cname result that we were told (if any) */
- char *cname_result;
-
- /* If we have one request answered and one request still inflight,
- * then this field holds the answer from the first request... */
- struct evutil_addrinfo *pending_result;
- /* And this event is a timeout that will tell us to cancel the second
- * request if it's taking a long time. */
- struct event timeout;
-
- /* And this field holds the error code from the first request... */
- int pending_error;
- /* If this is set, the user canceled this request. */
- unsigned user_canceled : 1;
- /* If this is set, the user can no longer cancel this request; we're
- * just waiting for the free. */
- unsigned request_done : 1;
-};
-
-/* Convert an evdns errors to the equivalent getaddrinfo error. */
-static int
-evdns_err_to_getaddrinfo_err(int e1)
-{
- /* XXX Do this better! */
- if (e1 == DNS_ERR_NONE)
- return 0;
- else if (e1 == DNS_ERR_NOTEXIST)
- return EVUTIL_EAI_NONAME;
- else
- return EVUTIL_EAI_FAIL;
-}
-
-/* Return the more informative of two getaddrinfo errors. */
-static int
-getaddrinfo_merge_err(int e1, int e2)
-{
- /* XXXX be cleverer here. */
- if (e1 == 0)
- return e2;
- else
- return e1;
-}
-
-static void
-free_getaddrinfo_request(struct evdns_getaddrinfo_request *data)
-{
- /* DO NOT CALL this if either of the requests is pending. Only once
- * both callbacks have been invoked is it safe to free the request */
- if (data->pending_result)
- evutil_freeaddrinfo(data->pending_result);
- if (data->cname_result)
- mm_free(data->cname_result);
- event_del(&data->timeout);
- mm_free(data);
- return;
-}
-
-static void
-add_cname_to_reply(struct evdns_getaddrinfo_request *data,
- struct evutil_addrinfo *ai)
-{
- if (data->cname_result && ai) {
- ai->ai_canonname = data->cname_result;
- data->cname_result = NULL;
- }
-}
-
-/* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo
- * request has finished, but the other one took too long to answer. Pass
- * along the answer we got, and cancel the other request.
- */
-static void
-evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
-{
- int v4_timedout = 0, v6_timedout = 0;
- struct evdns_getaddrinfo_request *data = ptr;
-
- /* Cancel any pending requests, and note which one */
- if (data->ipv4_request.r) {
- /* XXXX This does nothing if the request's callback is already
- * running (pending_cb is set). */
- evdns_cancel_request(NULL, data->ipv4_request.r);
- v4_timedout = 1;
- EVDNS_LOCK(data->evdns_base);
- ++data->evdns_base->getaddrinfo_ipv4_timeouts;
- EVDNS_UNLOCK(data->evdns_base);
- }
- if (data->ipv6_request.r) {
- /* XXXX This does nothing if the request's callback is already
- * running (pending_cb is set). */
- evdns_cancel_request(NULL, data->ipv6_request.r);
- v6_timedout = 1;
- EVDNS_LOCK(data->evdns_base);
- ++data->evdns_base->getaddrinfo_ipv6_timeouts;
- EVDNS_UNLOCK(data->evdns_base);
- }
-
- /* We only use this timeout callback when we have an answer for
- * one address. */
- EVUTIL_ASSERT(!v4_timedout || !v6_timedout);
-
- /* Report the outcome of the other request that didn't time out. */
- if (data->pending_result) {
- add_cname_to_reply(data, data->pending_result);
- data->user_cb(0, data->pending_result, data->user_data);
- data->pending_result = NULL;
- } else {
- int e = data->pending_error;
- if (!e)
- e = EVUTIL_EAI_AGAIN;
- data->user_cb(e, NULL, data->user_data);
- }
-
- data->user_cb = NULL; /* prevent double-call if evdns callbacks are
- * in-progress. XXXX It would be better if this
- * weren't necessary. */
-
- if (!v4_timedout && !v6_timedout) {
- /* should be impossible? XXXX */
- free_getaddrinfo_request(data);
- }
-}
-
-static int
-evdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base,
- struct evdns_getaddrinfo_request *data)
-{
- return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew);
-}
-
-static inline int
-evdns_result_is_answer(int result)
-{
- return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED &&
- result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL);
-}
-
-static void
-evdns_getaddrinfo_gotresolve(int result, char type, int count,
- int ttl, void *addresses, void *arg)
-{
- int i;
- struct getaddrinfo_subrequest *req = arg;
- struct getaddrinfo_subrequest *other_req;
- struct evdns_getaddrinfo_request *data;
-
- struct evutil_addrinfo *res;
-
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- struct sockaddr *sa;
- int socklen, addrlen;
- void *addrp;
- int err;
- int user_canceled;
-
- EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA);
- if (req->type == DNS_IPv4_A) {
- data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request);
- other_req = &data->ipv6_request;
- } else {
- data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request);
- other_req = &data->ipv4_request;
- }
-
- /** Called from evdns_base_free() with @fail_requests == 1 */
- if (result != DNS_ERR_SHUTDOWN) {
- EVDNS_LOCK(data->evdns_base);
- if (evdns_result_is_answer(result)) {
- if (req->type == DNS_IPv4_A)
- ++data->evdns_base->getaddrinfo_ipv4_answered;
- else
- ++data->evdns_base->getaddrinfo_ipv6_answered;
- }
- user_canceled = data->user_canceled;
- if (other_req->r == NULL)
- data->request_done = 1;
- EVDNS_UNLOCK(data->evdns_base);
- } else {
- data->evdns_base = NULL;
- user_canceled = data->user_canceled;
- }
-
- req->r = NULL;
-
- if (result == DNS_ERR_CANCEL && ! user_canceled) {
- /* Internal cancel request from timeout or internal error.
- * we already answered the user. */
- if (other_req->r == NULL)
- free_getaddrinfo_request(data);
- return;
- }
-
- if (data->user_cb == NULL) {
- /* We already answered. XXXX This shouldn't be needed; see
- * comments in evdns_getaddrinfo_timeout_cb */
- free_getaddrinfo_request(data);
- return;
- }
-
- if (result == DNS_ERR_NONE) {
- if (count == 0)
- err = EVUTIL_EAI_NODATA;
- else
- err = 0;
- } else {
- err = evdns_err_to_getaddrinfo_err(result);
- }
-
- if (err) {
- /* Looks like we got an error. */
- if (other_req->r) {
- /* The other request is still working; maybe it will
- * succeed. */
- /* XXXX handle failure from set_timeout */
- if (result != DNS_ERR_SHUTDOWN) {
- evdns_getaddrinfo_set_timeout(data->evdns_base, data);
- }
- data->pending_error = err;
- return;
- }
-
- if (user_canceled) {
- data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
- } else if (data->pending_result) {
- /* If we have an answer waiting, and we weren't
- * canceled, ignore this error. */
- add_cname_to_reply(data, data->pending_result);
- data->user_cb(0, data->pending_result, data->user_data);
- data->pending_result = NULL;
- } else {
- if (data->pending_error)
- err = getaddrinfo_merge_err(err,
- data->pending_error);
- data->user_cb(err, NULL, data->user_data);
- }
- free_getaddrinfo_request(data);
- return;
- } else if (user_canceled) {
- if (other_req->r) {
- /* The other request is still working; let it hit this
- * callback with EVUTIL_EAI_CANCEL callback and report
- * the failure. */
- return;
- }
- data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
- free_getaddrinfo_request(data);
- return;
- }
-
- /* Looks like we got some answers. We should turn them into addrinfos
- * and then either queue those or return them all. */
- EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA);
-
- if (type == DNS_IPv4_A) {
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(data->port);
-
- sa = (struct sockaddr *)&sin;
- socklen = sizeof(sin);
- addrlen = 4;
- addrp = &sin.sin_addr.s_addr;
- } else {
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(data->port);
-
- sa = (struct sockaddr *)&sin6;
- socklen = sizeof(sin6);
- addrlen = 16;
- addrp = &sin6.sin6_addr.s6_addr;
- }
-
- res = NULL;
- for (i=0; i < count; ++i) {
- struct evutil_addrinfo *ai;
- memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen);
- ai = evutil_new_addrinfo_(sa, socklen, &data->hints);
- if (!ai) {
- if (other_req->r) {
- evdns_cancel_request(NULL, other_req->r);
- }
- data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data);
- if (res)
- evutil_freeaddrinfo(res);
-
- if (other_req->r == NULL)
- free_getaddrinfo_request(data);
- return;
- }
- res = evutil_addrinfo_append_(res, ai);
- }
-
- if (other_req->r) {
- /* The other request is still in progress; wait for it */
- /* XXXX handle failure from set_timeout */
- evdns_getaddrinfo_set_timeout(data->evdns_base, data);
- data->pending_result = res;
- return;
- } else {
- /* The other request is done or never started; append its
- * results (if any) and return them. */
- if (data->pending_result) {
- if (req->type == DNS_IPv4_A)
- res = evutil_addrinfo_append_(res,
- data->pending_result);
- else
- res = evutil_addrinfo_append_(
- data->pending_result, res);
- data->pending_result = NULL;
- }
-
- /* Call the user callback. */
- add_cname_to_reply(data, res);
- data->user_cb(0, res, data->user_data);
-
- /* Free data. */
- free_getaddrinfo_request(data);
- }
-}
-
-static struct hosts_entry *
-find_hosts_entry(struct evdns_base *base, const char *hostname,
- struct hosts_entry *find_after)
-{
- struct hosts_entry *e;
-
- if (find_after)
- e = TAILQ_NEXT(find_after, next);
- else
- e = TAILQ_FIRST(&base->hostsdb);
-
- for (; e; e = TAILQ_NEXT(e, next)) {
- if (!evutil_ascii_strcasecmp(e->hostname, hostname))
- return e;
- }
- return NULL;
-}
-
-static int
-evdns_getaddrinfo_fromhosts(struct evdns_base *base,
- const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
- struct evutil_addrinfo **res)
-{
- int n_found = 0;
- struct hosts_entry *e;
- struct evutil_addrinfo *ai=NULL;
- int f = hints->ai_family;
-
- EVDNS_LOCK(base);
- for (e = find_hosts_entry(base, nodename, NULL); e;
- e = find_hosts_entry(base, nodename, e)) {
- struct evutil_addrinfo *ai_new;
- ++n_found;
- if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
- (e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
- continue;
- ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints);
- if (!ai_new) {
- n_found = 0;
- goto out;
- }
- sockaddr_setport(ai_new->ai_addr, port);
- ai = evutil_addrinfo_append_(ai, ai_new);
- }
- EVDNS_UNLOCK(base);
-out:
- if (n_found) {
- /* Note that we return an empty answer if we found entries for
- * this hostname but none were of the right address type. */
- *res = ai;
- return 0;
- } else {
- if (ai)
- evutil_freeaddrinfo(ai);
- return -1;
- }
-}
-
-struct evdns_getaddrinfo_request *
-evdns_getaddrinfo(struct evdns_base *dns_base,
- const char *nodename, const char *servname,
- const struct evutil_addrinfo *hints_in,
- evdns_getaddrinfo_cb cb, void *arg)
-{
- struct evdns_getaddrinfo_request *data;
- struct evutil_addrinfo hints;
- struct evutil_addrinfo *res = NULL;
- int err;
- int port = 0;
- int want_cname = 0;
-
- if (!dns_base) {
- dns_base = current_base;
- if (!dns_base) {
- log(EVDNS_LOG_WARN,
- "Call to getaddrinfo_async with no "
- "evdns_base configured.");
- cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */
- return NULL;
- }
- }
-
- /* If we _must_ answer this immediately, do so. */
- if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) {
- res = NULL;
- err = evutil_getaddrinfo(nodename, servname, hints_in, &res);
- cb(err, res, arg);
- return NULL;
- }
-
- if (hints_in) {
- memcpy(&hints, hints_in, sizeof(hints));
- } else {
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- }
-
- evutil_adjust_hints_for_addrconfig_(&hints);
-
- /* Now try to see if we _can_ answer immediately. */
- /* (It would be nice to do this by calling getaddrinfo directly, with
- * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't
- * a reliable way to distinguish the "that wasn't a numeric host!" case
- * from any other EAI_NONAME cases.) */
- err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port);
- if (err != EVUTIL_EAI_NEED_RESOLVE) {
- cb(err, res, arg);
- return NULL;
- }
-
- /* If there is an entry in the hosts file, we should give it now. */
- if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
- cb(0, res, arg);
- return NULL;
- }
-
- /* Okay, things are serious now. We're going to need to actually
- * launch a request.
- */
- data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request));
- if (!data) {
- cb(EVUTIL_EAI_MEMORY, NULL, arg);
- return NULL;
- }
-
- memcpy(&data->hints, &hints, sizeof(data->hints));
- data->port = (ev_uint16_t)port;
- data->ipv4_request.type = DNS_IPv4_A;
- data->ipv6_request.type = DNS_IPv6_AAAA;
- data->user_cb = cb;
- data->user_data = arg;
- data->evdns_base = dns_base;
-
- want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME);
-
- /* If we are asked for a PF_UNSPEC address, we launch two requests in
- * parallel: one for an A address and one for an AAAA address. We
- * can't send just one request, since many servers only answer one
- * question per DNS request.
- *
- * Once we have the answer to one request, we allow for a short
- * timeout before we report it, to see if the other one arrives. If
- * they both show up in time, then we report both the answers.
- *
- * If too many addresses of one type time out or fail, we should stop
- * launching those requests. (XXX we don't do that yet.)
- */
-
- if (hints.ai_family != PF_INET6) {
- log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
- nodename, &data->ipv4_request);
-
- data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
- nodename, 0, evdns_getaddrinfo_gotresolve,
- &data->ipv4_request);
- if (want_cname && data->ipv4_request.r)
- data->ipv4_request.r->current_req->put_cname_in_ptr =
- &data->cname_result;
- }
- if (hints.ai_family != PF_INET) {
- log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p",
- nodename, &data->ipv6_request);
-
- data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
- nodename, 0, evdns_getaddrinfo_gotresolve,
- &data->ipv6_request);
- if (want_cname && data->ipv6_request.r)
- data->ipv6_request.r->current_req->put_cname_in_ptr =
- &data->cname_result;
- }
-
- evtimer_assign(&data->timeout, dns_base->event_base,
- evdns_getaddrinfo_timeout_cb, data);
-
- if (data->ipv4_request.r || data->ipv6_request.r) {
- return data;
- } else {
- mm_free(data);
- cb(EVUTIL_EAI_FAIL, NULL, arg);
- return NULL;
- }
-}
-
-void
-evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data)
-{
- EVDNS_LOCK(data->evdns_base);
- if (data->request_done) {
- EVDNS_UNLOCK(data->evdns_base);
- return;
- }
- event_del(&data->timeout);
- data->user_canceled = 1;
- if (data->ipv4_request.r)
- evdns_cancel_request(data->evdns_base, data->ipv4_request.r);
- if (data->ipv6_request.r)
- evdns_cancel_request(data->evdns_base, data->ipv6_request.r);
- EVDNS_UNLOCK(data->evdns_base);
-}
diff --git a/libs/libevent/src/event-internal.h b/libs/libevent/src/event-internal.h
deleted file mode 100644
index 66dcfc329c..0000000000
--- a/libs/libevent/src/event-internal.h
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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_INCLUDED_
-#define EVENT_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <time.h>
-#include <sys/queue.h>
-#include "event2/event_struct.h"
-#include "minheap-internal.h"
-#include "evsignal-internal.h"
-#include "mm-internal.h"
-#include "defer-internal.h"
-
-/* map union members back */
-
-/* mutually exclusive */
-#define ev_signal_next ev_.ev_signal.ev_signal_next
-#define ev_io_next ev_.ev_io.ev_io_next
-#define ev_io_timeout ev_.ev_io.ev_timeout
-
-/* used only by signals */
-#define ev_ncalls ev_.ev_signal.ev_ncalls
-#define ev_pncalls ev_.ev_signal.ev_pncalls
-
-#define ev_pri ev_evcallback.evcb_pri
-#define ev_flags ev_evcallback.evcb_flags
-#define ev_closure ev_evcallback.evcb_closure
-#define ev_callback ev_evcallback.evcb_cb_union.evcb_callback
-#define ev_arg ev_evcallback.evcb_arg
-
-/** @name Event closure codes
-
- Possible values for evcb_closure in struct event_callback
-
- @{
- */
-/** A regular event. Uses the evcb_callback callback */
-#define EV_CLOSURE_EVENT 0
-/** A signal event. Uses the evcb_callback callback */
-#define EV_CLOSURE_EVENT_SIGNAL 1
-/** A persistent non-signal event. Uses the evcb_callback callback */
-#define EV_CLOSURE_EVENT_PERSIST 2
-/** A simple callback. Uses the evcb_selfcb callback. */
-#define EV_CLOSURE_CB_SELF 3
-/** A finalizing callback. Uses the evcb_cbfinalize callback. */
-#define EV_CLOSURE_CB_FINALIZE 4
-/** A finalizing event. Uses the evcb_evfinalize callback. */
-#define EV_CLOSURE_EVENT_FINALIZE 5
-/** A finalizing event that should get freed after. Uses the evcb_evfinalize
- * callback. */
-#define EV_CLOSURE_EVENT_FINALIZE_FREE 6
-/** @} */
-
-/** Structure to define the backend of a given event_base. */
-struct eventop {
- /** The name of this backend. */
- const char *name;
- /** Function to set up an event_base to use this backend. It should
- * create a new structure holding whatever information is needed to
- * run the backend, and return it. The returned pointer will get
- * stored by event_init into the event_base.evbase field. On failure,
- * this function should return NULL. */
- void *(*init)(struct event_base *);
- /** Enable reading/writing on a given fd or signal. 'events' will be
- * the events that we're trying to enable: one or more of EV_READ,
- * EV_WRITE, EV_SIGNAL, and EV_ET. 'old' will be those events that
- * were enabled on this fd previously. 'fdinfo' will be a structure
- * associated with the fd by the evmap; its size is defined by the
- * fdinfo field below. It will be set to 0 the first time the fd is
- * added. The function should return 0 on success and -1 on error.
- */
- int (*add)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
- /** As "add", except 'events' contains the events we mean to disable. */
- int (*del)(struct event_base *, evutil_socket_t fd, short old, short events, void *fdinfo);
- /** Function to implement the core of an event loop. It must see which
- added events are ready, and cause event_active to be called for each
- active event (usually via event_io_active or such). It should
- return 0 on success and -1 on error.
- */
- int (*dispatch)(struct event_base *, struct timeval *);
- /** Function to clean up and free our data from the event_base. */
- void (*dealloc)(struct event_base *);
- /** Flag: set if we need to reinitialize the event base after we fork.
- */
- int need_reinit;
- /** Bit-array of supported event_method_features that this backend can
- * provide. */
- enum event_method_feature features;
- /** Length of the extra information we should record for each fd that
- has one or more active events. This information is recorded
- as part of the evmap entry for each fd, and passed as an argument
- to the add and del functions above.
- */
- size_t fdinfo_len;
-};
-
-#ifdef _WIN32
-/* If we're on win32, then file descriptors are not nice low densely packed
- integers. Instead, they are pointer-like windows handles, and we want to
- use a hashtable instead of an array to map fds to events.
-*/
-#define EVMAP_USE_HT
-#endif
-
-/* #define HT_CACHE_HASH_VALS */
-
-#ifdef EVMAP_USE_HT
-#define HT_NO_CACHE_HASH_VALUES
-#include "ht-internal.h"
-struct event_map_entry;
-HT_HEAD(event_io_map, event_map_entry);
-#else
-#define event_io_map event_signal_map
-#endif
-
-/* Used to map signal numbers to a list of events. If EVMAP_USE_HT is not
- defined, this structure is also used as event_io_map, which maps fds to a
- list of events.
-*/
-struct event_signal_map {
- /* An array of evmap_io * or of evmap_signal *; empty entries are
- * set to NULL. */
- void **entries;
- /* The number of entries available in entries */
- int nentries;
-};
-
-/* A list of events waiting on a given 'common' timeout value. Ordinarily,
- * events waiting for a timeout wait on a minheap. Sometimes, however, a
- * queue can be faster.
- **/
-struct common_timeout_list {
- /* List of events currently waiting in the queue. */
- struct event_list events;
- /* 'magic' timeval used to indicate the duration of events in this
- * queue. */
- struct timeval duration;
- /* Event that triggers whenever one of the events in the queue is
- * ready to activate */
- struct event timeout_event;
- /* The event_base that this timeout list is part of */
- struct event_base *base;
-};
-
-/** Mask used to get the real tv_usec value from a common timeout. */
-#define COMMON_TIMEOUT_MICROSECONDS_MASK 0x000fffff
-
-struct event_change;
-
-/* List of 'changes' since the last call to eventop.dispatch. Only maintained
- * if the backend is using changesets. */
-struct event_changelist {
- struct event_change *changes;
- int n_changes;
- int changes_size;
-};
-
-#ifndef EVENT__DISABLE_DEBUG_MODE
-/* Global internal flag: set to one if debug mode is on. */
-extern int event_debug_mode_on_;
-#define EVENT_DEBUG_MODE_IS_ON() (event_debug_mode_on_)
-#else
-#define EVENT_DEBUG_MODE_IS_ON() (0)
-#endif
-
-TAILQ_HEAD(evcallback_list, event_callback);
-
-/* Sets up an event for processing once */
-struct event_once {
- LIST_ENTRY(event_once) next_once;
- struct event ev;
-
- void (*cb)(evutil_socket_t, short, void *);
- void *arg;
-};
-
-struct event_base {
- /** Function pointers and other data to describe this event_base's
- * backend. */
- const struct eventop *evsel;
- /** Pointer to backend-specific data. */
- void *evbase;
-
- /** List of changes to tell backend about at next dispatch. Only used
- * by the O(1) backends. */
- struct event_changelist changelist;
-
- /** Function pointers used to describe the backend that this event_base
- * uses for signals */
- const struct eventop *evsigsel;
- /** Data to implement the common signal handelr code. */
- struct evsig_info sig;
-
- /** Number of virtual events */
- int virtual_event_count;
- /** Maximum number of virtual events active */
- int virtual_event_count_max;
- /** Number of total events added to this event_base */
- int event_count;
- /** Maximum number of total events added to this event_base */
- int event_count_max;
- /** Number of total events active in this event_base */
- int event_count_active;
- /** Maximum number of total events active in this event_base */
- int event_count_active_max;
-
- /** Set if we should terminate the loop once we're done processing
- * events. */
- int event_gotterm;
- /** Set if we should terminate the loop immediately */
- int event_break;
- /** Set if we should start a new instance of the loop immediately. */
- int event_continue;
-
- /** The currently running priority of events */
- int event_running_priority;
-
- /** Set if we're running the event_base_loop function, to prevent
- * reentrant invocation. */
- int running_loop;
-
- /** Set to the number of deferred_cbs we've made 'active' in the
- * loop. This is a hack to prevent starvation; it would be smarter
- * to just use event_config_set_max_dispatch_interval's max_callbacks
- * feature */
- int n_deferreds_queued;
-
- /* Active event management. */
- /** An array of nactivequeues queues for active event_callbacks (ones
- * that have triggered, and whose callbacks need to be called). Low
- * priority numbers are more important, and stall higher ones.
- */
- struct evcallback_list *activequeues;
- /** The length of the activequeues array */
- int nactivequeues;
- /** A list of event_callbacks that should become active the next time
- * we process events, but not this time. */
- struct evcallback_list active_later_queue;
-
- /* common timeout logic */
-
- /** An array of common_timeout_list* for all of the common timeout
- * values we know. */
- struct common_timeout_list **common_timeout_queues;
- /** The number of entries used in common_timeout_queues */
- int n_common_timeouts;
- /** The total size of common_timeout_queues. */
- int n_common_timeouts_allocated;
-
- /** Mapping from file descriptors to enabled (added) events */
- struct event_io_map io;
-
- /** Mapping from signal numbers to enabled (added) events. */
- struct event_signal_map sigmap;
-
- /** Priority queue of events with timeouts. */
- struct min_heap timeheap;
-
- /** Stored timeval: used to avoid calling gettimeofday/clock_gettime
- * too often. */
- struct timeval tv_cache;
-
- struct evutil_monotonic_timer monotonic_timer;
-
- /** Difference between internal time (maybe from clock_gettime) and
- * gettimeofday. */
- struct timeval tv_clock_diff;
- /** Second in which we last updated tv_clock_diff, in monotonic time. */
- time_t last_updated_clock_diff;
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- /* threading support */
- /** The thread currently running the event_loop for this base */
- unsigned long th_owner_id;
- /** A lock to prevent conflicting accesses to this event_base */
- void *th_base_lock;
- /** A condition that gets signalled when we're done processing an
- * event with waiters on it. */
- void *current_event_cond;
- /** Number of threads blocking on current_event_cond. */
- int current_event_waiters;
-#endif
- /** The event whose callback is executing right now */
- struct event_callback *current_event;
-
-#ifdef _WIN32
- /** IOCP support structure, if IOCP is enabled. */
- struct event_iocp_port *iocp;
-#endif
-
- /** Flags that this base was configured with */
- enum event_base_config_flag flags;
-
- struct timeval max_dispatch_time;
- int max_dispatch_callbacks;
- int limit_callbacks_after_prio;
-
- /* Notify main thread to wake up break, etc. */
- /** True if the base already has a pending notify, and we don't need
- * to add any more. */
- int is_notify_pending;
- /** A socketpair used by some th_notify functions to wake up the main
- * thread. */
- evutil_socket_t th_notify_fd[2];
- /** An event used by some th_notify functions to wake up the main
- * thread. */
- struct event th_notify;
- /** A function used to wake up the main thread from another thread. */
- int (*th_notify_fn)(struct event_base *base);
-
- /** Saved seed for weak random number generator. Some backends use
- * this to produce fairness among sockets. Protected by th_base_lock. */
- struct evutil_weakrand_state weakrand_seed;
-
- /** List of event_onces that have not yet fired. */
- LIST_HEAD(once_event_list, event_once) once_events;
-
-};
-
-struct event_config_entry {
- TAILQ_ENTRY(event_config_entry) next;
-
- const char *avoid_method;
-};
-
-/** Internal structure: describes the configuration we want for an event_base
- * that we're about to allocate. */
-struct event_config {
- TAILQ_HEAD(event_configq, event_config_entry) entries;
-
- int n_cpus_hint;
- struct timeval max_dispatch_interval;
- int max_dispatch_callbacks;
- int limit_callbacks_after_prio;
- enum event_method_feature require_features;
- enum event_base_config_flag flags;
-};
-
-/* Internal use only: Functions that might be missing from <sys/queue.h> */
-#ifndef TAILQ_FIRST
-#define TAILQ_FIRST(head) ((head)->tqh_first)
-#endif
-#ifndef TAILQ_END
-#define TAILQ_END(head) NULL
-#endif
-#ifndef TAILQ_NEXT
-#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-#endif
-
-#ifndef TAILQ_FOREACH
-#define TAILQ_FOREACH(var, head, field) \
- for ((var) = TAILQ_FIRST(head); \
- (var) != TAILQ_END(head); \
- (var) = TAILQ_NEXT(var, field))
-#endif
-
-#ifndef TAILQ_INSERT_BEFORE
-#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
-
-#define N_ACTIVE_CALLBACKS(base) \
- ((base)->event_count_active)
-
-int evsig_set_handler_(struct event_base *base, int evsignal,
- void (*fn)(int));
-int evsig_restore_handler_(struct event_base *base, int evsignal);
-
-int event_add_nolock_(struct event *ev,
- const struct timeval *tv, int tv_is_absolute);
-/** Argument for event_del_nolock_. Tells event_del not to block on the event
- * if it's running in another thread. */
-#define EVENT_DEL_NOBLOCK 0
-/** Argument for event_del_nolock_. Tells event_del to block on the event
- * if it's running in another thread, regardless of its value for EV_FINALIZE
- */
-#define EVENT_DEL_BLOCK 1
-/** Argument for event_del_nolock_. Tells event_del to block on the event
- * if it is running in another thread and it doesn't have EV_FINALIZE set.
- */
-#define EVENT_DEL_AUTOBLOCK 2
-/** Argument for event_del_nolock_. Tells event_del to procede even if the
- * event is set up for finalization rather for regular use.*/
-#define EVENT_DEL_EVEN_IF_FINALIZING 3
-int event_del_nolock_(struct event *ev, int blocking);
-int event_remove_timer_nolock_(struct event *ev);
-
-void event_active_nolock_(struct event *ev, int res, short count);
-int event_callback_activate_(struct event_base *, struct event_callback *);
-int event_callback_activate_nolock_(struct event_base *, struct event_callback *);
-int event_callback_cancel_(struct event_base *base,
- struct event_callback *evcb);
-
-void event_callback_finalize_nolock_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *));
-void event_callback_finalize_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *));
-int event_callback_finalize_many_(struct event_base *base, int n_cbs, struct event_callback **evcb, void (*cb)(struct event_callback *, void *));
-
-
-void event_active_later_(struct event *ev, int res);
-void event_active_later_nolock_(struct event *ev, int res);
-int event_callback_activate_later_nolock_(struct event_base *base,
- struct event_callback *evcb);
-int event_callback_cancel_nolock_(struct event_base *base,
- struct event_callback *evcb, int even_if_finalizing);
-void event_callback_init_(struct event_base *base,
- struct event_callback *cb);
-
-/* FIXME document. */
-void event_base_add_virtual_(struct event_base *base);
-void event_base_del_virtual_(struct event_base *base);
-
-/** For debugging: unless assertions are disabled, verify the referential
- integrity of the internal data structures of 'base'. This operation can
- be expensive.
-
- Returns on success; aborts on failure.
-*/
-void event_base_assert_ok_(struct event_base *base);
-void event_base_assert_ok_nolock_(struct event_base *base);
-
-
-/* Helper function: Call 'fn' exactly once every inserted or active event in
- * the event_base 'base'.
- *
- * If fn returns 0, continue on to the next event. Otherwise, return the same
- * value that fn returned.
- *
- * Requires that 'base' be locked.
- */
-int event_base_foreach_event_nolock_(struct event_base *base,
- event_base_foreach_event_cb cb, void *arg);
-
-/* Cleanup function to reset debug mode during shutdown.
- *
- * Calling this function doesn't mean it'll be possible to re-enable
- * debug mode if any events were added.
- */
-void event_disable_debug_mode(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* EVENT_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/event.c b/libs/libevent/src/event.c
deleted file mode 100644
index 503003e249..0000000000
--- a/libs/libevent/src/event.c
+++ /dev/null
@@ -1,3940 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#endif
-#include <sys/types.h>
-#if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
-#include <sys/time.h>
-#endif
-#include <sys/queue.h>
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <limits.h>
-
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "event2/event_compat.h"
-#include "event-internal.h"
-#include "defer-internal.h"
-#include "evthread-internal.h"
-#include "event2/thread.h"
-#include "event2/util.h"
-#include "log-internal.h"
-#include "evmap-internal.h"
-#include "iocp-internal.h"
-#include "changelist-internal.h"
-#define HT_NO_CACHE_HASH_VALUES
-#include "ht-internal.h"
-#include "util-internal.h"
-
-
-#ifdef EVENT__HAVE_WORKING_KQUEUE
-#include "kqueue-internal.h"
-#endif
-
-#ifdef EVENT__HAVE_EVENT_PORTS
-extern const struct eventop evportops;
-#endif
-#ifdef EVENT__HAVE_SELECT
-extern const struct eventop selectops;
-#endif
-#ifdef EVENT__HAVE_POLL
-extern const struct eventop pollops;
-#endif
-#ifdef EVENT__HAVE_EPOLL
-extern const struct eventop epollops;
-#endif
-#ifdef EVENT__HAVE_WORKING_KQUEUE
-extern const struct eventop kqops;
-#endif
-#ifdef EVENT__HAVE_DEVPOLL
-extern const struct eventop devpollops;
-#endif
-#ifdef _WIN32
-extern const struct eventop win32ops;
-#endif
-
-/* Array of backends in order of preference. */
-static const struct eventop *eventops[] = {
-#ifdef EVENT__HAVE_EVENT_PORTS
- &evportops,
-#endif
-#ifdef EVENT__HAVE_WORKING_KQUEUE
- &kqops,
-#endif
-#ifdef EVENT__HAVE_EPOLL
- &epollops,
-#endif
-#ifdef EVENT__HAVE_DEVPOLL
- &devpollops,
-#endif
-#ifdef EVENT__HAVE_POLL
- &pollops,
-#endif
-#ifdef EVENT__HAVE_SELECT
- &selectops,
-#endif
-#ifdef _WIN32
- &win32ops,
-#endif
- NULL
-};
-
-/* Global state; deprecated */
-struct event_base *event_global_current_base_ = NULL;
-#define current_base event_global_current_base_
-
-/* Global state */
-
-static void *event_self_cbarg_ptr_ = NULL;
-
-/* Prototypes */
-static void event_queue_insert_active(struct event_base *, struct event_callback *);
-static void event_queue_insert_active_later(struct event_base *, struct event_callback *);
-static void event_queue_insert_timeout(struct event_base *, struct event *);
-static void event_queue_insert_inserted(struct event_base *, struct event *);
-static void event_queue_remove_active(struct event_base *, struct event_callback *);
-static void event_queue_remove_active_later(struct event_base *, struct event_callback *);
-static void event_queue_remove_timeout(struct event_base *, struct event *);
-static void event_queue_remove_inserted(struct event_base *, struct event *);
-static void event_queue_make_later_events_active(struct event_base *base);
-
-static int evthread_make_base_notifiable_nolock_(struct event_base *base);
-static int event_del_(struct event *ev, int blocking);
-
-#ifdef USE_REINSERT_TIMEOUT
-/* This code seems buggy; only turn it on if we find out what the trouble is. */
-static void event_queue_reinsert_timeout(struct event_base *,struct event *, int was_common, int is_common, int old_timeout_idx);
-#endif
-
-static int event_haveevents(struct event_base *);
-
-static int event_process_active(struct event_base *);
-
-static int timeout_next(struct event_base *, struct timeval **);
-static void timeout_process(struct event_base *);
-
-static inline void event_signal_closure(struct event_base *, struct event *ev);
-static inline void event_persist_closure(struct event_base *, struct event *ev);
-
-static int evthread_notify_base(struct event_base *base);
-
-static void insert_common_timeout_inorder(struct common_timeout_list *ctl,
- struct event *ev);
-
-#ifndef EVENT__DISABLE_DEBUG_MODE
-/* These functions implement a hashtable of which 'struct event *' structures
- * have been setup or added. We don't want to trust the content of the struct
- * event itself, since we're trying to work through cases where an event gets
- * clobbered or freed. Instead, we keep a hashtable indexed by the pointer.
- */
-
-struct event_debug_entry {
- HT_ENTRY(event_debug_entry) node;
- const struct event *ptr;
- unsigned added : 1;
-};
-
-static inline unsigned
-hash_debug_entry(const struct event_debug_entry *e)
-{
- /* We need to do this silliness to convince compilers that we
- * honestly mean to cast e->ptr to an integer, and discard any
- * part of it that doesn't fit in an unsigned.
- */
- unsigned u = (unsigned) ((ev_uintptr_t) e->ptr);
- /* Our hashtable implementation is pretty sensitive to low bits,
- * and every struct event is over 64 bytes in size, so we can
- * just say >>6. */
- return (u >> 6);
-}
-
-static inline int
-eq_debug_entry(const struct event_debug_entry *a,
- const struct event_debug_entry *b)
-{
- return a->ptr == b->ptr;
-}
-
-int event_debug_mode_on_ = 0;
-
-
-#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
-/**
- * @brief debug mode variable which is set for any function/structure that needs
- * to be shared across threads (if thread support is enabled).
- *
- * When and if evthreads are initialized, this variable will be evaluated,
- * and if set to something other than zero, this means the evthread setup
- * functions were called out of order.
- *
- * See: "Locks and threading" in the documentation.
- */
-int event_debug_created_threadable_ctx_ = 0;
-#endif
-
-/* Set if it's too late to enable event_debug_mode. */
-static int event_debug_mode_too_late = 0;
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-static void *event_debug_map_lock_ = NULL;
-#endif
-static HT_HEAD(event_debug_map, event_debug_entry) global_debug_map =
- HT_INITIALIZER();
-
-HT_PROTOTYPE(event_debug_map, event_debug_entry, node, hash_debug_entry,
- eq_debug_entry)
-HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
- eq_debug_entry, 0.5, mm_malloc, mm_realloc, mm_free)
-
-/* Macro: record that ev is now setup (that is, ready for an add) */
-#define event_debug_note_setup_(ev) do { \
- if (event_debug_mode_on_) { \
- struct event_debug_entry *dent,find; \
- find.ptr = (ev); \
- EVLOCK_LOCK(event_debug_map_lock_, 0); \
- dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
- if (dent) { \
- dent->added = 0; \
- } else { \
- dent = mm_malloc(sizeof(*dent)); \
- if (!dent) \
- event_err(1, \
- "Out of memory in debugging code"); \
- dent->ptr = (ev); \
- dent->added = 0; \
- HT_INSERT(event_debug_map, &global_debug_map, dent); \
- } \
- EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
- } \
- event_debug_mode_too_late = 1; \
- } while (0)
-/* Macro: record that ev is no longer setup */
-#define event_debug_note_teardown_(ev) do { \
- if (event_debug_mode_on_) { \
- struct event_debug_entry *dent,find; \
- find.ptr = (ev); \
- EVLOCK_LOCK(event_debug_map_lock_, 0); \
- dent = HT_REMOVE(event_debug_map, &global_debug_map, &find); \
- if (dent) \
- mm_free(dent); \
- EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
- } \
- event_debug_mode_too_late = 1; \
- } while (0)
-/* Macro: record that ev is now added */
-#define event_debug_note_add_(ev) do { \
- if (event_debug_mode_on_) { \
- struct event_debug_entry *dent,find; \
- find.ptr = (ev); \
- EVLOCK_LOCK(event_debug_map_lock_, 0); \
- dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
- if (dent) { \
- dent->added = 1; \
- } else { \
- event_errx(EVENT_ERR_ABORT_, \
- "%s: noting an add on a non-setup event %p" \
- " (events: 0x%x, fd: "EV_SOCK_FMT \
- ", flags: 0x%x)", \
- __func__, (ev), (ev)->ev_events, \
- EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
- } \
- EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
- } \
- event_debug_mode_too_late = 1; \
- } while (0)
-/* Macro: record that ev is no longer added */
-#define event_debug_note_del_(ev) do { \
- if (event_debug_mode_on_) { \
- struct event_debug_entry *dent,find; \
- find.ptr = (ev); \
- EVLOCK_LOCK(event_debug_map_lock_, 0); \
- dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
- if (dent) { \
- dent->added = 0; \
- } else { \
- event_errx(EVENT_ERR_ABORT_, \
- "%s: noting a del on a non-setup event %p" \
- " (events: 0x%x, fd: "EV_SOCK_FMT \
- ", flags: 0x%x)", \
- __func__, (ev), (ev)->ev_events, \
- EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
- } \
- EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
- } \
- event_debug_mode_too_late = 1; \
- } while (0)
-/* Macro: assert that ev is setup (i.e., okay to add or inspect) */
-#define event_debug_assert_is_setup_(ev) do { \
- if (event_debug_mode_on_) { \
- struct event_debug_entry *dent,find; \
- find.ptr = (ev); \
- EVLOCK_LOCK(event_debug_map_lock_, 0); \
- dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
- if (!dent) { \
- event_errx(EVENT_ERR_ABORT_, \
- "%s called on a non-initialized event %p" \
- " (events: 0x%x, fd: "EV_SOCK_FMT\
- ", flags: 0x%x)", \
- __func__, (ev), (ev)->ev_events, \
- EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
- } \
- EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
- } \
- } while (0)
-/* Macro: assert that ev is not added (i.e., okay to tear down or set
- * up again) */
-#define event_debug_assert_not_added_(ev) do { \
- if (event_debug_mode_on_) { \
- struct event_debug_entry *dent,find; \
- find.ptr = (ev); \
- EVLOCK_LOCK(event_debug_map_lock_, 0); \
- dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
- if (dent && dent->added) { \
- event_errx(EVENT_ERR_ABORT_, \
- "%s called on an already added event %p" \
- " (events: 0x%x, fd: "EV_SOCK_FMT", " \
- "flags: 0x%x)", \
- __func__, (ev), (ev)->ev_events, \
- EV_SOCK_ARG((ev)->ev_fd), (ev)->ev_flags); \
- } \
- EVLOCK_UNLOCK(event_debug_map_lock_, 0); \
- } \
- } while (0)
-#else
-#define event_debug_note_setup_(ev) \
- ((void)0)
-#define event_debug_note_teardown_(ev) \
- ((void)0)
-#define event_debug_note_add_(ev) \
- ((void)0)
-#define event_debug_note_del_(ev) \
- ((void)0)
-#define event_debug_assert_is_setup_(ev) \
- ((void)0)
-#define event_debug_assert_not_added_(ev) \
- ((void)0)
-#endif
-
-#define EVENT_BASE_ASSERT_LOCKED(base) \
- EVLOCK_ASSERT_LOCKED((base)->th_base_lock)
-
-/* How often (in seconds) do we check for changes in wall clock time relative
- * to monotonic time? Set this to -1 for 'never.' */
-#define CLOCK_SYNC_INTERVAL 5
-
-/** Set 'tp' to the current time according to 'base'. We must hold the lock
- * on 'base'. If there is a cached time, return it. Otherwise, use
- * clock_gettime or gettimeofday as appropriate to find out the right time.
- * Return 0 on success, -1 on failure.
- */
-static int
-gettime(struct event_base *base, struct timeval *tp)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
-
- if (base->tv_cache.tv_sec) {
- *tp = base->tv_cache;
- return (0);
- }
-
- if (evutil_gettime_monotonic_(&base->monotonic_timer, tp) == -1) {
- return -1;
- }
-
- if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL
- < tp->tv_sec) {
- struct timeval tv;
- evutil_gettimeofday(&tv,NULL);
- evutil_timersub(&tv, tp, &base->tv_clock_diff);
- base->last_updated_clock_diff = tp->tv_sec;
- }
-
- return 0;
-}
-
-int
-event_base_gettimeofday_cached(struct event_base *base, struct timeval *tv)
-{
- int r;
- if (!base) {
- base = current_base;
- if (!current_base)
- return evutil_gettimeofday(tv, NULL);
- }
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- if (base->tv_cache.tv_sec == 0) {
- r = evutil_gettimeofday(tv, NULL);
- } else {
- evutil_timeradd(&base->tv_cache, &base->tv_clock_diff, tv);
- r = 0;
- }
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-/** Make 'base' have no current cached time. */
-static inline void
-clear_time_cache(struct event_base *base)
-{
- base->tv_cache.tv_sec = 0;
-}
-
-/** Replace the cached time in 'base' with the current time. */
-static inline void
-update_time_cache(struct event_base *base)
-{
- base->tv_cache.tv_sec = 0;
- if (!(base->flags & EVENT_BASE_FLAG_NO_CACHE_TIME))
- gettime(base, &base->tv_cache);
-}
-
-int
-event_base_update_cache_time(struct event_base *base)
-{
-
- if (!base) {
- base = current_base;
- if (!current_base)
- return -1;
- }
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- if (base->running_loop)
- update_time_cache(base);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return 0;
-}
-
-static inline struct event *
-event_callback_to_event(struct event_callback *evcb)
-{
- EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_INIT));
- return EVUTIL_UPCAST(evcb, struct event, ev_evcallback);
-}
-
-static inline struct event_callback *
-event_to_event_callback(struct event *ev)
-{
- return &ev->ev_evcallback;
-}
-
-struct event_base *
-event_init(void)
-{
- struct event_base *base = event_base_new_with_config(NULL);
-
- if (base == NULL) {
- event_errx(1, "%s: Unable to construct event_base", __func__);
- return NULL;
- }
-
- current_base = base;
-
- return (base);
-}
-
-struct event_base *
-event_base_new(void)
-{
- struct event_base *base = NULL;
- struct event_config *cfg = event_config_new();
- if (cfg) {
- base = event_base_new_with_config(cfg);
- event_config_free(cfg);
- }
- return base;
-}
-
-/** Return true iff 'method' is the name of a method that 'cfg' tells us to
- * avoid. */
-static int
-event_config_is_avoided_method(const struct event_config *cfg,
- const char *method)
-{
- struct event_config_entry *entry;
-
- TAILQ_FOREACH(entry, &cfg->entries, next) {
- if (entry->avoid_method != NULL &&
- strcmp(entry->avoid_method, method) == 0)
- return (1);
- }
-
- return (0);
-}
-
-/** Return true iff 'method' is disabled according to the environment. */
-static int
-event_is_method_disabled(const char *name)
-{
- char environment[64];
- int i;
-
- evutil_snprintf(environment, sizeof(environment), "EVENT_NO%s", name);
- for (i = 8; environment[i] != '\0'; ++i)
- environment[i] = EVUTIL_TOUPPER_(environment[i]);
- /* Note that evutil_getenv_() ignores the environment entirely if
- * we're setuid */
- return (evutil_getenv_(environment) != NULL);
-}
-
-int
-event_base_get_features(const struct event_base *base)
-{
- return base->evsel->features;
-}
-
-void
-event_enable_debug_mode(void)
-{
-#ifndef EVENT__DISABLE_DEBUG_MODE
- if (event_debug_mode_on_)
- event_errx(1, "%s was called twice!", __func__);
- if (event_debug_mode_too_late)
- event_errx(1, "%s must be called *before* creating any events "
- "or event_bases",__func__);
-
- event_debug_mode_on_ = 1;
-
- HT_INIT(event_debug_map, &global_debug_map);
-#endif
-}
-
-void
-event_disable_debug_mode(void)
-{
-#ifndef EVENT__DISABLE_DEBUG_MODE
- struct event_debug_entry **ent, *victim;
-
- EVLOCK_LOCK(event_debug_map_lock_, 0);
- for (ent = HT_START(event_debug_map, &global_debug_map); ent; ) {
- victim = *ent;
- ent = HT_NEXT_RMV(event_debug_map, &global_debug_map, ent);
- mm_free(victim);
- }
- HT_CLEAR(event_debug_map, &global_debug_map);
- EVLOCK_UNLOCK(event_debug_map_lock_ , 0);
-
- event_debug_mode_on_ = 0;
-#endif
-}
-
-struct event_base *
-event_base_new_with_config(const struct event_config *cfg)
-{
- int i;
- struct event_base *base;
- int should_check_environment;
-
-#ifndef EVENT__DISABLE_DEBUG_MODE
- event_debug_mode_too_late = 1;
-#endif
-
- if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) {
- event_warn("%s: calloc", __func__);
- return NULL;
- }
-
- if (cfg)
- base->flags = cfg->flags;
-
- should_check_environment =
- !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
-
- {
- struct timeval tmp;
- int precise_time =
- cfg && (cfg->flags & EVENT_BASE_FLAG_PRECISE_TIMER);
- int flags;
- if (should_check_environment && !precise_time) {
- precise_time = evutil_getenv_("EVENT_PRECISE_TIMER") != NULL;
- base->flags |= EVENT_BASE_FLAG_PRECISE_TIMER;
- }
- flags = precise_time ? EV_MONOT_PRECISE : 0;
- evutil_configure_monotonic_time_(&base->monotonic_timer, flags);
-
- gettime(base, &tmp);
- }
-
- min_heap_ctor_(&base->timeheap);
-
- base->sig.ev_signal_pair[0] = -1;
- base->sig.ev_signal_pair[1] = -1;
- base->th_notify_fd[0] = -1;
- base->th_notify_fd[1] = -1;
-
- TAILQ_INIT(&base->active_later_queue);
-
- evmap_io_initmap_(&base->io);
- evmap_signal_initmap_(&base->sigmap);
- event_changelist_init_(&base->changelist);
-
- base->evbase = NULL;
-
- if (cfg) {
- memcpy(&base->max_dispatch_time,
- &cfg->max_dispatch_interval, sizeof(struct timeval));
- base->limit_callbacks_after_prio =
- cfg->limit_callbacks_after_prio;
- } else {
- base->max_dispatch_time.tv_sec = -1;
- base->limit_callbacks_after_prio = 1;
- }
- if (cfg && cfg->max_dispatch_callbacks >= 0) {
- base->max_dispatch_callbacks = cfg->max_dispatch_callbacks;
- } else {
- base->max_dispatch_callbacks = INT_MAX;
- }
- if (base->max_dispatch_callbacks == INT_MAX &&
- base->max_dispatch_time.tv_sec == -1)
- base->limit_callbacks_after_prio = INT_MAX;
-
- for (i = 0; eventops[i] && !base->evbase; i++) {
- if (cfg != NULL) {
- /* determine if this backend should be avoided */
- if (event_config_is_avoided_method(cfg,
- eventops[i]->name))
- continue;
- if ((eventops[i]->features & cfg->require_features)
- != cfg->require_features)
- continue;
- }
-
- /* also obey the environment variables */
- if (should_check_environment &&
- event_is_method_disabled(eventops[i]->name))
- continue;
-
- base->evsel = eventops[i];
-
- base->evbase = base->evsel->init(base);
- }
-
- if (base->evbase == NULL) {
- event_warnx("%s: no event mechanism available",
- __func__);
- base->evsel = NULL;
- event_base_free(base);
- return NULL;
- }
-
- if (evutil_getenv_("EVENT_SHOW_METHOD"))
- event_msgx("libevent using: %s", base->evsel->name);
-
- /* allocate a single active event queue */
- if (event_base_priority_init(base, 1) < 0) {
- event_base_free(base);
- return NULL;
- }
-
- /* prepare for threading */
-
-#if !defined(EVENT__DISABLE_THREAD_SUPPORT) && !defined(EVENT__DISABLE_DEBUG_MODE)
- event_debug_created_threadable_ctx_ = 1;
-#endif
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (EVTHREAD_LOCKING_ENABLED() &&
- (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK))) {
- int r;
- EVTHREAD_ALLOC_LOCK(base->th_base_lock, 0);
- EVTHREAD_ALLOC_COND(base->current_event_cond);
- r = evthread_make_base_notifiable(base);
- if (r<0) {
- event_warnx("%s: Unable to make base notifiable.", __func__);
- event_base_free(base);
- return NULL;
- }
- }
-#endif
-
-#ifdef _WIN32
- if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
- event_base_start_iocp_(base, cfg->n_cpus_hint);
-#endif
-
- return (base);
-}
-
-int
-event_base_start_iocp_(struct event_base *base, int n_cpus)
-{
-#ifdef _WIN32
- if (base->iocp)
- return 0;
- base->iocp = event_iocp_port_launch_(n_cpus);
- if (!base->iocp) {
- event_warnx("%s: Couldn't launch IOCP", __func__);
- return -1;
- }
- return 0;
-#else
- return -1;
-#endif
-}
-
-void
-event_base_stop_iocp_(struct event_base *base)
-{
-#ifdef _WIN32
- int rv;
-
- if (!base->iocp)
- return;
- rv = event_iocp_shutdown_(base->iocp, -1);
- EVUTIL_ASSERT(rv >= 0);
- base->iocp = NULL;
-#endif
-}
-
-static int
-event_base_cancel_single_callback_(struct event_base *base,
- struct event_callback *evcb,
- int run_finalizers)
-{
- int result = 0;
-
- if (evcb->evcb_flags & EVLIST_INIT) {
- struct event *ev = event_callback_to_event(evcb);
- if (!(ev->ev_flags & EVLIST_INTERNAL)) {
- event_del_(ev, EVENT_DEL_EVEN_IF_FINALIZING);
- result = 1;
- }
- } else {
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- event_callback_cancel_nolock_(base, evcb, 1);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- result = 1;
- }
-
- if (run_finalizers && (evcb->evcb_flags & EVLIST_FINALIZING)) {
- switch (evcb->evcb_closure) {
- case EV_CLOSURE_EVENT_FINALIZE:
- case EV_CLOSURE_EVENT_FINALIZE_FREE: {
- struct event *ev = event_callback_to_event(evcb);
- ev->ev_evcallback.evcb_cb_union.evcb_evfinalize(ev, ev->ev_arg);
- if (evcb->evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
- mm_free(ev);
- break;
- }
- case EV_CLOSURE_CB_FINALIZE:
- evcb->evcb_cb_union.evcb_cbfinalize(evcb, evcb->evcb_arg);
- break;
- default:
- break;
- }
- }
- return result;
-}
-
-static int event_base_free_queues_(struct event_base *base, int run_finalizers)
-{
- int deleted = 0, i;
-
- for (i = 0; i < base->nactivequeues; ++i) {
- struct event_callback *evcb, *next;
- for (evcb = TAILQ_FIRST(&base->activequeues[i]); evcb; ) {
- next = TAILQ_NEXT(evcb, evcb_active_next);
- deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
- evcb = next;
- }
- }
-
- {
- struct event_callback *evcb;
- while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
- deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
- }
- }
-
- return deleted;
-}
-
-static void
-event_base_free_(struct event_base *base, int run_finalizers)
-{
- int i, n_deleted=0;
- struct event *ev;
- /* XXXX grab the lock? If there is contention when one thread frees
- * the base, then the contending thread will be very sad soon. */
-
- /* event_base_free(NULL) is how to free the current_base if we
- * made it with event_init and forgot to hold a reference to it. */
- if (base == NULL && current_base)
- base = current_base;
- /* Don't actually free NULL. */
- if (base == NULL) {
- event_warnx("%s: no base to free", __func__);
- return;
- }
- /* XXX(niels) - check for internal events first */
-
-#ifdef _WIN32
- event_base_stop_iocp_(base);
-#endif
-
- /* threading fds if we have them */
- if (base->th_notify_fd[0] != -1) {
- event_del(&base->th_notify);
- EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
- if (base->th_notify_fd[1] != -1)
- EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
- base->th_notify_fd[0] = -1;
- base->th_notify_fd[1] = -1;
- event_debug_unassign(&base->th_notify);
- }
-
- /* Delete all non-internal events. */
- evmap_delete_all_(base);
-
- while ((ev = min_heap_top_(&base->timeheap)) != NULL) {
- event_del(ev);
- ++n_deleted;
- }
- for (i = 0; i < base->n_common_timeouts; ++i) {
- struct common_timeout_list *ctl =
- base->common_timeout_queues[i];
- event_del(&ctl->timeout_event); /* Internal; doesn't count */
- event_debug_unassign(&ctl->timeout_event);
- for (ev = TAILQ_FIRST(&ctl->events); ev; ) {
- struct event *next = TAILQ_NEXT(ev,
- ev_timeout_pos.ev_next_with_common_timeout);
- if (!(ev->ev_flags & EVLIST_INTERNAL)) {
- event_del(ev);
- ++n_deleted;
- }
- ev = next;
- }
- mm_free(ctl);
- }
- if (base->common_timeout_queues)
- mm_free(base->common_timeout_queues);
-
- for (;;) {
- /* For finalizers we can register yet another finalizer out from
- * finalizer, and iff finalizer will be in active_later_queue we can
- * add finalizer to activequeues, and we will have events in
- * activequeues after this function returns, which is not what we want
- * (we even have an assertion for this).
- *
- * A simple case is bufferevent with underlying (i.e. filters).
- */
- int i = event_base_free_queues_(base, run_finalizers);
- if (!i) {
- break;
- }
- n_deleted += i;
- }
-
- if (n_deleted)
- event_debug(("%s: %d events were still set in base",
- __func__, n_deleted));
-
- while (LIST_FIRST(&base->once_events)) {
- struct event_once *eonce = LIST_FIRST(&base->once_events);
- LIST_REMOVE(eonce, next_once);
- mm_free(eonce);
- }
-
- if (base->evsel != NULL && base->evsel->dealloc != NULL)
- base->evsel->dealloc(base);
-
- for (i = 0; i < base->nactivequeues; ++i)
- EVUTIL_ASSERT(TAILQ_EMPTY(&base->activequeues[i]));
-
- EVUTIL_ASSERT(min_heap_empty_(&base->timeheap));
- min_heap_dtor_(&base->timeheap);
-
- mm_free(base->activequeues);
-
- evmap_io_clear_(&base->io);
- evmap_signal_clear_(&base->sigmap);
- event_changelist_freemem_(&base->changelist);
-
- EVTHREAD_FREE_LOCK(base->th_base_lock, 0);
- EVTHREAD_FREE_COND(base->current_event_cond);
-
- /* If we're freeing current_base, there won't be a current_base. */
- if (base == current_base)
- current_base = NULL;
- mm_free(base);
-}
-
-void
-event_base_free_nofinalize(struct event_base *base)
-{
- event_base_free_(base, 0);
-}
-
-void
-event_base_free(struct event_base *base)
-{
- event_base_free_(base, 1);
-}
-
-/* Fake eventop; used to disable the backend temporarily inside event_reinit
- * so that we can call event_del() on an event without telling the backend.
- */
-static int
-nil_backend_del(struct event_base *b, evutil_socket_t fd, short old,
- short events, void *fdinfo)
-{
- return 0;
-}
-const struct eventop nil_eventop = {
- "nil",
- NULL, /* init: unused. */
- NULL, /* add: unused. */
- nil_backend_del, /* del: used, so needs to be killed. */
- NULL, /* dispatch: unused. */
- NULL, /* dealloc: unused. */
- 0, 0, 0
-};
-
-/* reinitialize the event base after a fork */
-int
-event_reinit(struct event_base *base)
-{
- const struct eventop *evsel;
- int res = 0;
- int was_notifiable = 0;
- int had_signal_added = 0;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- evsel = base->evsel;
-
- /* check if this event mechanism requires reinit on the backend */
- if (evsel->need_reinit) {
- /* We're going to call event_del() on our notify events (the
- * ones that tell about signals and wakeup events). But we
- * don't actually want to tell the backend to change its
- * state, since it might still share some resource (a kqueue,
- * an epoll fd) with the parent process, and we don't want to
- * delete the fds from _that_ backend, we temporarily stub out
- * the evsel with a replacement.
- */
- base->evsel = &nil_eventop;
- }
-
- /* We need to re-create a new signal-notification fd and a new
- * thread-notification fd. Otherwise, we'll still share those with
- * the parent process, which would make any notification sent to them
- * get received by one or both of the event loops, more or less at
- * random.
- */
- if (base->sig.ev_signal_added) {
- event_del_nolock_(&base->sig.ev_signal, EVENT_DEL_AUTOBLOCK);
- event_debug_unassign(&base->sig.ev_signal);
- memset(&base->sig.ev_signal, 0, sizeof(base->sig.ev_signal));
- had_signal_added = 1;
- base->sig.ev_signal_added = 0;
- }
- if (base->sig.ev_signal_pair[0] != -1)
- EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
- if (base->sig.ev_signal_pair[1] != -1)
- EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
- if (base->th_notify_fn != NULL) {
- was_notifiable = 1;
- base->th_notify_fn = NULL;
- }
- if (base->th_notify_fd[0] != -1) {
- event_del_nolock_(&base->th_notify, EVENT_DEL_AUTOBLOCK);
- EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
- if (base->th_notify_fd[1] != -1)
- EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
- base->th_notify_fd[0] = -1;
- base->th_notify_fd[1] = -1;
- event_debug_unassign(&base->th_notify);
- }
-
- /* Replace the original evsel. */
- base->evsel = evsel;
-
- if (evsel->need_reinit) {
- /* Reconstruct the backend through brute-force, so that we do
- * not share any structures with the parent process. For some
- * backends, this is necessary: epoll and kqueue, for
- * instance, have events associated with a kernel
- * structure. If didn't reinitialize, we'd share that
- * structure with the parent process, and any changes made by
- * the parent would affect our backend's behavior (and vice
- * versa).
- */
- if (base->evsel->dealloc != NULL)
- base->evsel->dealloc(base);
- base->evbase = evsel->init(base);
- if (base->evbase == NULL) {
- event_errx(1,
- "%s: could not reinitialize event mechanism",
- __func__);
- res = -1;
- goto done;
- }
-
- /* Empty out the changelist (if any): we are starting from a
- * blank slate. */
- event_changelist_freemem_(&base->changelist);
-
- /* Tell the event maps to re-inform the backend about all
- * pending events. This will make the signal notification
- * event get re-created if necessary. */
- if (evmap_reinit_(base) < 0)
- res = -1;
- } else {
- res = evsig_init_(base);
- if (res == 0 && had_signal_added) {
- res = event_add_nolock_(&base->sig.ev_signal, NULL, 0);
- if (res == 0)
- base->sig.ev_signal_added = 1;
- }
- }
-
- /* If we were notifiable before, and nothing just exploded, become
- * notifiable again. */
- if (was_notifiable && res == 0)
- res = evthread_make_base_notifiable_nolock_(base);
-
-done:
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return (res);
-}
-
-/* Get the monotonic time for this event_base' timer */
-int
-event_gettime_monotonic(struct event_base *base, struct timeval *tv)
-{
- int rv = -1;
-
- if (base && tv) {
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- rv = evutil_gettime_monotonic_(&(base->monotonic_timer), tv);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- }
-
- return rv;
-}
-
-const char **
-event_get_supported_methods(void)
-{
- static const char **methods = NULL;
- const struct eventop **method;
- const char **tmp;
- int i = 0, k;
-
- /* count all methods */
- for (method = &eventops[0]; *method != NULL; ++method) {
- ++i;
- }
-
- /* allocate one more than we need for the NULL pointer */
- tmp = mm_calloc((i + 1), sizeof(char *));
- if (tmp == NULL)
- return (NULL);
-
- /* populate the array with the supported methods */
- for (k = 0, i = 0; eventops[k] != NULL; ++k) {
- tmp[i++] = eventops[k]->name;
- }
- tmp[i] = NULL;
-
- if (methods != NULL)
- mm_free((char**)methods);
-
- methods = tmp;
-
- return (methods);
-}
-
-struct event_config *
-event_config_new(void)
-{
- struct event_config *cfg = mm_calloc(1, sizeof(*cfg));
-
- if (cfg == NULL)
- return (NULL);
-
- TAILQ_INIT(&cfg->entries);
- cfg->max_dispatch_interval.tv_sec = -1;
- cfg->max_dispatch_callbacks = INT_MAX;
- cfg->limit_callbacks_after_prio = 1;
-
- return (cfg);
-}
-
-static void
-event_config_entry_free(struct event_config_entry *entry)
-{
- if (entry->avoid_method != NULL)
- mm_free((char *)entry->avoid_method);
- mm_free(entry);
-}
-
-void
-event_config_free(struct event_config *cfg)
-{
- struct event_config_entry *entry;
-
- while ((entry = TAILQ_FIRST(&cfg->entries)) != NULL) {
- TAILQ_REMOVE(&cfg->entries, entry, next);
- event_config_entry_free(entry);
- }
- mm_free(cfg);
-}
-
-int
-event_config_set_flag(struct event_config *cfg, int flag)
-{
- if (!cfg)
- return -1;
- cfg->flags |= flag;
- return 0;
-}
-
-int
-event_config_avoid_method(struct event_config *cfg, const char *method)
-{
- struct event_config_entry *entry = mm_malloc(sizeof(*entry));
- if (entry == NULL)
- return (-1);
-
- if ((entry->avoid_method = mm_strdup(method)) == NULL) {
- mm_free(entry);
- return (-1);
- }
-
- TAILQ_INSERT_TAIL(&cfg->entries, entry, next);
-
- return (0);
-}
-
-int
-event_config_require_features(struct event_config *cfg,
- int features)
-{
- if (!cfg)
- return (-1);
- cfg->require_features = features;
- return (0);
-}
-
-int
-event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)
-{
- if (!cfg)
- return (-1);
- cfg->n_cpus_hint = cpus;
- return (0);
-}
-
-int
-event_config_set_max_dispatch_interval(struct event_config *cfg,
- const struct timeval *max_interval, int max_callbacks, int min_priority)
-{
- if (max_interval)
- memcpy(&cfg->max_dispatch_interval, max_interval,
- sizeof(struct timeval));
- else
- cfg->max_dispatch_interval.tv_sec = -1;
- cfg->max_dispatch_callbacks =
- max_callbacks >= 0 ? max_callbacks : INT_MAX;
- if (min_priority < 0)
- min_priority = 0;
- cfg->limit_callbacks_after_prio = min_priority;
- return (0);
-}
-
-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, r;
- r = -1;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- if (N_ACTIVE_CALLBACKS(base) || npriorities < 1
- || npriorities >= EVENT_MAX_PRIORITIES)
- goto err;
-
- if (npriorities == base->nactivequeues)
- goto ok;
-
- if (base->nactivequeues) {
- mm_free(base->activequeues);
- base->nactivequeues = 0;
- }
-
- /* Allocate our priority queues */
- base->activequeues = (struct evcallback_list *)
- mm_calloc(npriorities, sizeof(struct evcallback_list));
- if (base->activequeues == NULL) {
- event_warn("%s: calloc", __func__);
- goto err;
- }
- base->nactivequeues = npriorities;
-
- for (i = 0; i < base->nactivequeues; ++i) {
- TAILQ_INIT(&base->activequeues[i]);
- }
-
-ok:
- r = 0;
-err:
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return (r);
-}
-
-int
-event_base_get_npriorities(struct event_base *base)
-{
-
- int n;
- if (base == NULL)
- base = current_base;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- n = base->nactivequeues;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return (n);
-}
-
-int
-event_base_get_num_events(struct event_base *base, unsigned int type)
-{
- int r = 0;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- if (type & EVENT_BASE_COUNT_ACTIVE)
- r += base->event_count_active;
-
- if (type & EVENT_BASE_COUNT_VIRTUAL)
- r += base->virtual_event_count;
-
- if (type & EVENT_BASE_COUNT_ADDED)
- r += base->event_count;
-
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-
- return r;
-}
-
-int
-event_base_get_max_events(struct event_base *base, unsigned int type, int clear)
-{
- int r = 0;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- if (type & EVENT_BASE_COUNT_ACTIVE) {
- r += base->event_count_active_max;
- if (clear)
- base->event_count_active_max = 0;
- }
-
- if (type & EVENT_BASE_COUNT_VIRTUAL) {
- r += base->virtual_event_count_max;
- if (clear)
- base->virtual_event_count_max = 0;
- }
-
- if (type & EVENT_BASE_COUNT_ADDED) {
- r += base->event_count_max;
- if (clear)
- base->event_count_max = 0;
- }
-
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-
- return r;
-}
-
-/* Returns true iff we're currently watching any events. */
-static int
-event_haveevents(struct event_base *base)
-{
- /* Caller must hold th_base_lock */
- return (base->virtual_event_count > 0 || base->event_count > 0);
-}
-
-/* "closure" function called when processing active signal events */
-static inline void
-event_signal_closure(struct event_base *base, struct event *ev)
-{
- short ncalls;
- int should_break;
-
- /* Allows deletes to work */
- ncalls = ev->ev_ncalls;
- if (ncalls != 0)
- ev->ev_pncalls = &ncalls;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- while (ncalls) {
- ncalls--;
- ev->ev_ncalls = ncalls;
- if (ncalls == 0)
- ev->ev_pncalls = NULL;
- (*ev->ev_callback)(ev->ev_fd, ev->ev_res, ev->ev_arg);
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- should_break = base->event_break;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-
- if (should_break) {
- if (ncalls != 0)
- ev->ev_pncalls = NULL;
- return;
- }
- }
-}
-
-/* Common timeouts are special timeouts that are handled as queues rather than
- * in the minheap. This is more efficient than the minheap if we happen to
- * know that we're going to get several thousands of timeout events all with
- * the same timeout value.
- *
- * Since all our timeout handling code assumes timevals can be copied,
- * assigned, etc, we can't use "magic pointer" to encode these common
- * timeouts. Searching through a list to see if every timeout is common could
- * also get inefficient. Instead, we take advantage of the fact that tv_usec
- * is 32 bits long, but only uses 20 of those bits (since it can never be over
- * 999999.) We use the top bits to encode 4 bites of magic number, and 8 bits
- * of index into the event_base's aray of common timeouts.
- */
-
-#define MICROSECONDS_MASK COMMON_TIMEOUT_MICROSECONDS_MASK
-#define COMMON_TIMEOUT_IDX_MASK 0x0ff00000
-#define COMMON_TIMEOUT_IDX_SHIFT 20
-#define COMMON_TIMEOUT_MASK 0xf0000000
-#define COMMON_TIMEOUT_MAGIC 0x50000000
-
-#define COMMON_TIMEOUT_IDX(tv) \
- (((tv)->tv_usec & COMMON_TIMEOUT_IDX_MASK)>>COMMON_TIMEOUT_IDX_SHIFT)
-
-/** Return true iff if 'tv' is a common timeout in 'base' */
-static inline int
-is_common_timeout(const struct timeval *tv,
- const struct event_base *base)
-{
- int idx;
- if ((tv->tv_usec & COMMON_TIMEOUT_MASK) != COMMON_TIMEOUT_MAGIC)
- return 0;
- idx = COMMON_TIMEOUT_IDX(tv);
- return idx < base->n_common_timeouts;
-}
-
-/* True iff tv1 and tv2 have the same common-timeout index, or if neither
- * one is a common timeout. */
-static inline int
-is_same_common_timeout(const struct timeval *tv1, const struct timeval *tv2)
-{
- return (tv1->tv_usec & ~MICROSECONDS_MASK) ==
- (tv2->tv_usec & ~MICROSECONDS_MASK);
-}
-
-/** Requires that 'tv' is a common timeout. Return the corresponding
- * common_timeout_list. */
-static inline struct common_timeout_list *
-get_common_timeout_list(struct event_base *base, const struct timeval *tv)
-{
- return base->common_timeout_queues[COMMON_TIMEOUT_IDX(tv)];
-}
-
-#if 0
-static inline int
-common_timeout_ok(const struct timeval *tv,
- struct event_base *base)
-{
- const struct timeval *expect =
- &get_common_timeout_list(base, tv)->duration;
- return tv->tv_sec == expect->tv_sec &&
- tv->tv_usec == expect->tv_usec;
-}
-#endif
-
-/* Add the timeout for the first event in given common timeout list to the
- * event_base's minheap. */
-static void
-common_timeout_schedule(struct common_timeout_list *ctl,
- const struct timeval *now, struct event *head)
-{
- struct timeval timeout = head->ev_timeout;
- timeout.tv_usec &= MICROSECONDS_MASK;
- event_add_nolock_(&ctl->timeout_event, &timeout, 1);
-}
-
-/* Callback: invoked when the timeout for a common timeout queue triggers.
- * This means that (at least) the first event in that queue should be run,
- * and the timeout should be rescheduled if there are more events. */
-static void
-common_timeout_callback(evutil_socket_t fd, short what, void *arg)
-{
- struct timeval now;
- struct common_timeout_list *ctl = arg;
- struct event_base *base = ctl->base;
- struct event *ev = NULL;
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- gettime(base, &now);
- while (1) {
- ev = TAILQ_FIRST(&ctl->events);
- if (!ev || ev->ev_timeout.tv_sec > now.tv_sec ||
- (ev->ev_timeout.tv_sec == now.tv_sec &&
- (ev->ev_timeout.tv_usec&MICROSECONDS_MASK) > now.tv_usec))
- break;
- event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
- event_active_nolock_(ev, EV_TIMEOUT, 1);
- }
- if (ev)
- common_timeout_schedule(ctl, &now, ev);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-#define MAX_COMMON_TIMEOUTS 256
-
-const struct timeval *
-event_base_init_common_timeout(struct event_base *base,
- const struct timeval *duration)
-{
- int i;
- struct timeval tv;
- const struct timeval *result=NULL;
- struct common_timeout_list *new_ctl;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- if (duration->tv_usec > 1000000) {
- memcpy(&tv, duration, sizeof(struct timeval));
- if (is_common_timeout(duration, base))
- tv.tv_usec &= MICROSECONDS_MASK;
- tv.tv_sec += tv.tv_usec / 1000000;
- tv.tv_usec %= 1000000;
- duration = &tv;
- }
- for (i = 0; i < base->n_common_timeouts; ++i) {
- const struct common_timeout_list *ctl =
- base->common_timeout_queues[i];
- if (duration->tv_sec == ctl->duration.tv_sec &&
- duration->tv_usec ==
- (ctl->duration.tv_usec & MICROSECONDS_MASK)) {
- EVUTIL_ASSERT(is_common_timeout(&ctl->duration, base));
- result = &ctl->duration;
- goto done;
- }
- }
- if (base->n_common_timeouts == MAX_COMMON_TIMEOUTS) {
- event_warnx("%s: Too many common timeouts already in use; "
- "we only support %d per event_base", __func__,
- MAX_COMMON_TIMEOUTS);
- goto done;
- }
- if (base->n_common_timeouts_allocated == base->n_common_timeouts) {
- int n = base->n_common_timeouts < 16 ? 16 :
- base->n_common_timeouts*2;
- struct common_timeout_list **newqueues =
- mm_realloc(base->common_timeout_queues,
- n*sizeof(struct common_timeout_queue *));
- if (!newqueues) {
- event_warn("%s: realloc",__func__);
- goto done;
- }
- base->n_common_timeouts_allocated = n;
- base->common_timeout_queues = newqueues;
- }
- new_ctl = mm_calloc(1, sizeof(struct common_timeout_list));
- if (!new_ctl) {
- event_warn("%s: calloc",__func__);
- goto done;
- }
- TAILQ_INIT(&new_ctl->events);
- new_ctl->duration.tv_sec = duration->tv_sec;
- new_ctl->duration.tv_usec =
- duration->tv_usec | COMMON_TIMEOUT_MAGIC |
- (base->n_common_timeouts << COMMON_TIMEOUT_IDX_SHIFT);
- evtimer_assign(&new_ctl->timeout_event, base,
- common_timeout_callback, new_ctl);
- new_ctl->timeout_event.ev_flags |= EVLIST_INTERNAL;
- event_priority_set(&new_ctl->timeout_event, 0);
- new_ctl->base = base;
- base->common_timeout_queues[base->n_common_timeouts++] = new_ctl;
- result = &new_ctl->duration;
-
-done:
- if (result)
- EVUTIL_ASSERT(is_common_timeout(result, base));
-
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return result;
-}
-
-/* Closure function invoked when we're activating a persistent event. */
-static inline void
-event_persist_closure(struct event_base *base, struct event *ev)
-{
- void (*evcb_callback)(evutil_socket_t, short, void *);
-
- // Other fields of *ev that must be stored before executing
- evutil_socket_t evcb_fd;
- short evcb_res;
- void *evcb_arg;
-
- /* reschedule the persistent event if we have a timeout. */
- if (ev->ev_io_timeout.tv_sec || ev->ev_io_timeout.tv_usec) {
- /* If there was a timeout, we want it to run at an interval of
- * ev_io_timeout after the last time it was _scheduled_ for,
- * not ev_io_timeout after _now_. If it fired for another
- * reason, though, the timeout ought to start ticking _now_. */
- struct timeval run_at, relative_to, delay, now;
- ev_uint32_t usec_mask = 0;
- EVUTIL_ASSERT(is_same_common_timeout(&ev->ev_timeout,
- &ev->ev_io_timeout));
- gettime(base, &now);
- if (is_common_timeout(&ev->ev_timeout, base)) {
- delay = ev->ev_io_timeout;
- usec_mask = delay.tv_usec & ~MICROSECONDS_MASK;
- delay.tv_usec &= MICROSECONDS_MASK;
- if (ev->ev_res & EV_TIMEOUT) {
- relative_to = ev->ev_timeout;
- relative_to.tv_usec &= MICROSECONDS_MASK;
- } else {
- relative_to = now;
- }
- } else {
- delay = ev->ev_io_timeout;
- if (ev->ev_res & EV_TIMEOUT) {
- relative_to = ev->ev_timeout;
- } else {
- relative_to = now;
- }
- }
- evutil_timeradd(&relative_to, &delay, &run_at);
- if (evutil_timercmp(&run_at, &now, <)) {
- /* Looks like we missed at least one invocation due to
- * a clock jump, not running the event loop for a
- * while, really slow callbacks, or
- * something. Reschedule relative to now.
- */
- evutil_timeradd(&now, &delay, &run_at);
- }
- run_at.tv_usec |= usec_mask;
- event_add_nolock_(ev, &run_at, 1);
- }
-
- // Save our callback before we release the lock
- evcb_callback = ev->ev_callback;
- evcb_fd = ev->ev_fd;
- evcb_res = ev->ev_res;
- evcb_arg = ev->ev_arg;
-
- // Release the lock
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-
- // Execute the callback
- (evcb_callback)(evcb_fd, evcb_res, evcb_arg);
-}
-
-/*
- Helper for event_process_active to process all the events in a single queue,
- releasing the lock as we go. This function requires that the lock be held
- when it's invoked. Returns -1 if we get a signal or an event_break that
- means we should stop processing any active events now. Otherwise returns
- the number of non-internal event_callbacks that we processed.
-*/
-static int
-event_process_active_single_queue(struct event_base *base,
- struct evcallback_list *activeq,
- int max_to_process, const struct timeval *endtime)
-{
- struct event_callback *evcb;
- int count = 0;
-
- EVUTIL_ASSERT(activeq != NULL);
-
- for (evcb = TAILQ_FIRST(activeq); evcb; evcb = TAILQ_FIRST(activeq)) {
- struct event *ev=NULL;
- if (evcb->evcb_flags & EVLIST_INIT) {
- ev = event_callback_to_event(evcb);
-
- if (ev->ev_events & EV_PERSIST || ev->ev_flags & EVLIST_FINALIZING)
- event_queue_remove_active(base, evcb);
- else
- event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
- event_debug((
- "event_process_active: event: %p, %s%s%scall %p",
- ev,
- ev->ev_res & EV_READ ? "EV_READ " : " ",
- ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
- ev->ev_res & EV_CLOSED ? "EV_CLOSED " : " ",
- ev->ev_callback));
- } else {
- event_queue_remove_active(base, evcb);
- event_debug(("event_process_active: event_callback %p, "
- "closure %d, call %p",
- evcb, evcb->evcb_closure, evcb->evcb_cb_union.evcb_callback));
- }
-
- if (!(evcb->evcb_flags & EVLIST_INTERNAL))
- ++count;
-
-
- base->current_event = evcb;
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- base->current_event_waiters = 0;
-#endif
-
- switch (evcb->evcb_closure) {
- case EV_CLOSURE_EVENT_SIGNAL:
- EVUTIL_ASSERT(ev != NULL);
- event_signal_closure(base, ev);
- break;
- case EV_CLOSURE_EVENT_PERSIST:
- EVUTIL_ASSERT(ev != NULL);
- event_persist_closure(base, ev);
- break;
- case EV_CLOSURE_EVENT: {
- void (*evcb_callback)(evutil_socket_t, short, void *);
- EVUTIL_ASSERT(ev != NULL);
- evcb_callback = *ev->ev_callback;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- evcb_callback(ev->ev_fd, ev->ev_res, ev->ev_arg);
- }
- break;
- case EV_CLOSURE_CB_SELF: {
- void (*evcb_selfcb)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_selfcb;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- evcb_selfcb(evcb, evcb->evcb_arg);
- }
- break;
- case EV_CLOSURE_EVENT_FINALIZE:
- case EV_CLOSURE_EVENT_FINALIZE_FREE: {
- void (*evcb_evfinalize)(struct event *, void *);
- int evcb_closure = evcb->evcb_closure;
- EVUTIL_ASSERT(ev != NULL);
- base->current_event = NULL;
- evcb_evfinalize = ev->ev_evcallback.evcb_cb_union.evcb_evfinalize;
- EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- evcb_evfinalize(ev, ev->ev_arg);
- event_debug_note_teardown_(ev);
- if (evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
- mm_free(ev);
- }
- break;
- case EV_CLOSURE_CB_FINALIZE: {
- void (*evcb_cbfinalize)(struct event_callback *, void *) = evcb->evcb_cb_union.evcb_cbfinalize;
- base->current_event = NULL;
- EVUTIL_ASSERT((evcb->evcb_flags & EVLIST_FINALIZING));
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- evcb_cbfinalize(evcb, evcb->evcb_arg);
- }
- break;
- default:
- EVUTIL_ASSERT(0);
- }
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- base->current_event = NULL;
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (base->current_event_waiters) {
- base->current_event_waiters = 0;
- EVTHREAD_COND_BROADCAST(base->current_event_cond);
- }
-#endif
-
- if (base->event_break)
- return -1;
- if (count >= max_to_process)
- return count;
- if (count && endtime) {
- struct timeval now;
- update_time_cache(base);
- gettime(base, &now);
- if (evutil_timercmp(&now, endtime, >=))
- return count;
- }
- if (base->event_continue)
- break;
- }
- return count;
-}
-
-/*
- * Active events are stored in priority queues. Lower priorities are always
- * process before higher priorities. Low priority events can starve high
- * priority ones.
- */
-
-static int
-event_process_active(struct event_base *base)
-{
- /* Caller must hold th_base_lock */
- struct evcallback_list *activeq = NULL;
- int i, c = 0;
- const struct timeval *endtime;
- struct timeval tv;
- const int maxcb = base->max_dispatch_callbacks;
- const int limit_after_prio = base->limit_callbacks_after_prio;
- if (base->max_dispatch_time.tv_sec >= 0) {
- update_time_cache(base);
- gettime(base, &tv);
- evutil_timeradd(&base->max_dispatch_time, &tv, &tv);
- endtime = &tv;
- } else {
- endtime = NULL;
- }
-
- for (i = 0; i < base->nactivequeues; ++i) {
- if (TAILQ_FIRST(&base->activequeues[i]) != NULL) {
- base->event_running_priority = i;
- activeq = &base->activequeues[i];
- if (i < limit_after_prio)
- c = event_process_active_single_queue(base, activeq,
- INT_MAX, NULL);
- else
- c = event_process_active_single_queue(base, activeq,
- maxcb, endtime);
- if (c < 0) {
- goto done;
- } else if (c > 0)
- break; /* Processed a real event; do not
- * consider lower-priority events */
- /* If we get here, all of the events we processed
- * were internal. Continue. */
- }
- }
-
-done:
- base->event_running_priority = -1;
-
- return c;
-}
-
-/*
- * Wait continuously 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(const struct event_base *base)
-{
- EVUTIL_ASSERT(base);
- return (base->evsel->name);
-}
-
-/** Callback: used to implement event_base_loopexit by telling the event_base
- * that it's time to exit its loop. */
-static void
-event_loopexit_cb(evutil_socket_t fd, short what, void *arg)
-{
- struct event_base *base = arg;
- base->event_gotterm = 1;
-}
-
-int
-event_loopexit(const struct timeval *tv)
-{
- return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
- current_base, tv));
-}
-
-int
-event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
-{
- return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
- event_base, tv));
-}
-
-int
-event_loopbreak(void)
-{
- return (event_base_loopbreak(current_base));
-}
-
-int
-event_base_loopbreak(struct event_base *event_base)
-{
- int r = 0;
- if (event_base == NULL)
- return (-1);
-
- EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
- event_base->event_break = 1;
-
- if (EVBASE_NEED_NOTIFY(event_base)) {
- r = evthread_notify_base(event_base);
- } else {
- r = (0);
- }
- EVBASE_RELEASE_LOCK(event_base, th_base_lock);
- return r;
-}
-
-int
-event_base_loopcontinue(struct event_base *event_base)
-{
- int r = 0;
- if (event_base == NULL)
- return (-1);
-
- EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
- event_base->event_continue = 1;
-
- if (EVBASE_NEED_NOTIFY(event_base)) {
- r = evthread_notify_base(event_base);
- } else {
- r = (0);
- }
- EVBASE_RELEASE_LOCK(event_base, th_base_lock);
- return r;
-}
-
-int
-event_base_got_break(struct event_base *event_base)
-{
- int res;
- EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
- res = event_base->event_break;
- EVBASE_RELEASE_LOCK(event_base, th_base_lock);
- return res;
-}
-
-int
-event_base_got_exit(struct event_base *event_base)
-{
- int res;
- EVBASE_ACQUIRE_LOCK(event_base, th_base_lock);
- res = event_base->event_gotterm;
- EVBASE_RELEASE_LOCK(event_base, th_base_lock);
- return res;
-}
-
-/* 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;
- struct timeval tv;
- struct timeval *tv_p;
- int res, done, retval = 0;
-
- /* Grab the lock. We will release it inside evsel.dispatch, and again
- * as we invoke user callbacks. */
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- if (base->running_loop) {
- event_warnx("%s: reentrant invocation. Only one event_base_loop"
- " can run on each event_base at once.", __func__);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return -1;
- }
-
- base->running_loop = 1;
-
- clear_time_cache(base);
-
- if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
- evsig_set_base_(base);
-
- done = 0;
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- base->th_owner_id = EVTHREAD_GET_ID();
-#endif
-
- base->event_gotterm = base->event_break = 0;
-
- while (!done) {
- base->event_continue = 0;
- base->n_deferreds_queued = 0;
-
- /* Terminate the loop if we have been asked to */
- if (base->event_gotterm) {
- break;
- }
-
- if (base->event_break) {
- break;
- }
-
- tv_p = &tv;
- if (!N_ACTIVE_CALLBACKS(base) && !(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 (0==(flags&EVLOOP_NO_EXIT_ON_EMPTY) &&
- !event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
- event_debug(("%s: no events registered.", __func__));
- retval = 1;
- goto done;
- }
-
- event_queue_make_later_events_active(base);
-
- clear_time_cache(base);
-
- res = evsel->dispatch(base, tv_p);
-
- if (res == -1) {
- event_debug(("%s: dispatch returned unsuccessfully.",
- __func__));
- retval = -1;
- goto done;
- }
-
- update_time_cache(base);
-
- timeout_process(base);
-
- if (N_ACTIVE_CALLBACKS(base)) {
- int n = event_process_active(base);
- if ((flags & EVLOOP_ONCE)
- && N_ACTIVE_CALLBACKS(base) == 0
- && n != 0)
- done = 1;
- } else if (flags & EVLOOP_NONBLOCK)
- done = 1;
- }
- event_debug(("%s: asked to terminate loop.", __func__));
-
-done:
- clear_time_cache(base);
- base->running_loop = 0;
-
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-
- return (retval);
-}
-
-/* One-time callback to implement event_base_once: invokes the user callback,
- * then deletes the allocated storage */
-static void
-event_once_cb(evutil_socket_t fd, short events, void *arg)
-{
- struct event_once *eonce = arg;
-
- (*eonce->cb)(fd, events, eonce->arg);
- EVBASE_ACQUIRE_LOCK(eonce->ev.ev_base, th_base_lock);
- LIST_REMOVE(eonce, next_once);
- EVBASE_RELEASE_LOCK(eonce->ev.ev_base, th_base_lock);
- event_debug_unassign(&eonce->ev);
- mm_free(eonce);
-}
-
-/* not threadsafe, event scheduled once. */
-int
-event_once(evutil_socket_t fd, short events,
- void (*callback)(evutil_socket_t, short, void *),
- void *arg, const struct timeval *tv)
-{
- return event_base_once(current_base, fd, events, callback, arg, tv);
-}
-
-/* Schedules an event once */
-int
-event_base_once(struct event_base *base, evutil_socket_t fd, short events,
- void (*callback)(evutil_socket_t, short, void *),
- void *arg, const struct timeval *tv)
-{
- struct event_once *eonce;
- int res = 0;
- int activate = 0;
-
- /* We cannot support signals that just fire once, or persistent
- * events. */
- if (events & (EV_SIGNAL|EV_PERSIST))
- return (-1);
-
- if ((eonce = mm_calloc(1, sizeof(struct event_once))) == NULL)
- return (-1);
-
- eonce->cb = callback;
- eonce->arg = arg;
-
- if ((events & (EV_TIMEOUT|EV_SIGNAL|EV_READ|EV_WRITE|EV_CLOSED)) == EV_TIMEOUT) {
- evtimer_assign(&eonce->ev, base, event_once_cb, eonce);
-
- if (tv == NULL || ! evutil_timerisset(tv)) {
- /* If the event is going to become active immediately,
- * don't put it on the timeout queue. This is one
- * idiom for scheduling a callback, so let's make
- * it fast (and order-preserving). */
- activate = 1;
- }
- } else if (events & (EV_READ|EV_WRITE|EV_CLOSED)) {
- events &= EV_READ|EV_WRITE|EV_CLOSED;
-
- event_assign(&eonce->ev, base, fd, events, event_once_cb, eonce);
- } else {
- /* Bad event combination */
- mm_free(eonce);
- return (-1);
- }
-
- if (res == 0) {
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- if (activate)
- event_active_nolock_(&eonce->ev, EV_TIMEOUT, 1);
- else
- res = event_add_nolock_(&eonce->ev, tv, 0);
-
- if (res != 0) {
- mm_free(eonce);
- return (res);
- } else {
- LIST_INSERT_HEAD(&base->once_events, eonce, next_once);
- }
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- }
-
- return (0);
-}
-
-int
-event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
-{
- if (!base)
- base = current_base;
- if (arg == &event_self_cbarg_ptr_)
- arg = ev;
-
- event_debug_assert_not_added_(ev);
-
- ev->ev_base = 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;
-
- if (events & EV_SIGNAL) {
- if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
- event_warnx("%s: EV_SIGNAL is not compatible with "
- "EV_READ, EV_WRITE or EV_CLOSED", __func__);
- return -1;
- }
- ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
- } else {
- if (events & EV_PERSIST) {
- evutil_timerclear(&ev->ev_io_timeout);
- ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
- } else {
- ev->ev_closure = EV_CLOSURE_EVENT;
- }
- }
-
- min_heap_elem_init_(ev);
-
- if (base != NULL) {
- /* by default, we put new events into the middle priority */
- ev->ev_pri = base->nactivequeues / 2;
- }
-
- event_debug_note_setup_(ev);
-
- return 0;
-}
-
-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);
-
- event_debug_assert_is_setup_(ev);
-
- ev->ev_base = base;
- ev->ev_pri = base->nactivequeues/2;
-
- return (0);
-}
-
-void
-event_set(struct event *ev, evutil_socket_t fd, short events,
- void (*callback)(evutil_socket_t, short, void *), void *arg)
-{
- int r;
- r = event_assign(ev, current_base, fd, events, callback, arg);
- EVUTIL_ASSERT(r == 0);
-}
-
-void *
-event_self_cbarg(void)
-{
- return &event_self_cbarg_ptr_;
-}
-
-struct event *
-event_base_get_running_event(struct event_base *base)
-{
- struct event *ev = NULL;
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- if (EVBASE_IN_THREAD(base)) {
- struct event_callback *evcb = base->current_event;
- if (evcb->evcb_flags & EVLIST_INIT)
- ev = event_callback_to_event(evcb);
- }
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return ev;
-}
-
-struct event *
-event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
-{
- struct event *ev;
- ev = mm_malloc(sizeof(struct event));
- if (ev == NULL)
- return (NULL);
- if (event_assign(ev, base, fd, events, cb, arg) < 0) {
- mm_free(ev);
- return (NULL);
- }
-
- return (ev);
-}
-
-void
-event_free(struct event *ev)
-{
- /* This is disabled, so that events which have been finalized be a
- * valid target for event_free(). That's */
- // event_debug_assert_is_setup_(ev);
-
- /* make sure that this event won't be coming back to haunt us. */
- event_del(ev);
- event_debug_note_teardown_(ev);
- mm_free(ev);
-
-}
-
-void
-event_debug_unassign(struct event *ev)
-{
- event_debug_assert_not_added_(ev);
- event_debug_note_teardown_(ev);
-
- ev->ev_flags &= ~EVLIST_INIT;
-}
-
-#define EVENT_FINALIZE_FREE_ 0x10000
-static int
-event_finalize_nolock_(struct event_base *base, unsigned flags, struct event *ev, event_finalize_callback_fn cb)
-{
- ev_uint8_t closure = (flags & EVENT_FINALIZE_FREE_) ?
- EV_CLOSURE_EVENT_FINALIZE_FREE : EV_CLOSURE_EVENT_FINALIZE;
-
- event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
- ev->ev_closure = closure;
- ev->ev_evcallback.evcb_cb_union.evcb_evfinalize = cb;
- event_active_nolock_(ev, EV_FINALIZE, 1);
- ev->ev_flags |= EVLIST_FINALIZING;
- return 0;
-}
-
-static int
-event_finalize_impl_(unsigned flags, struct event *ev, event_finalize_callback_fn cb)
-{
- int r;
- struct event_base *base = ev->ev_base;
- if (EVUTIL_FAILURE_CHECK(!base)) {
- event_warnx("%s: event has no event_base set.", __func__);
- return -1;
- }
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- r = event_finalize_nolock_(base, flags, ev, cb);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-int
-event_finalize(unsigned flags, struct event *ev, event_finalize_callback_fn cb)
-{
- return event_finalize_impl_(flags, ev, cb);
-}
-
-int
-event_free_finalize(unsigned flags, struct event *ev, event_finalize_callback_fn cb)
-{
- return event_finalize_impl_(flags|EVENT_FINALIZE_FREE_, ev, cb);
-}
-
-void
-event_callback_finalize_nolock_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *))
-{
- struct event *ev = NULL;
- if (evcb->evcb_flags & EVLIST_INIT) {
- ev = event_callback_to_event(evcb);
- event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
- } else {
- event_callback_cancel_nolock_(base, evcb, 0); /*XXX can this fail?*/
- }
-
- evcb->evcb_closure = EV_CLOSURE_CB_FINALIZE;
- evcb->evcb_cb_union.evcb_cbfinalize = cb;
- event_callback_activate_nolock_(base, evcb); /* XXX can this really fail?*/
- evcb->evcb_flags |= EVLIST_FINALIZING;
-}
-
-void
-event_callback_finalize_(struct event_base *base, unsigned flags, struct event_callback *evcb, void (*cb)(struct event_callback *, void *))
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- event_callback_finalize_nolock_(base, flags, evcb, cb);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-/** Internal: Finalize all of the n_cbs callbacks in evcbs. The provided
- * callback will be invoked on *one of them*, after they have *all* been
- * finalized. */
-int
-event_callback_finalize_many_(struct event_base *base, int n_cbs, struct event_callback **evcbs, void (*cb)(struct event_callback *, void *))
-{
- int n_pending = 0, i;
-
- if (base == NULL)
- base = current_base;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- event_debug(("%s: %d events finalizing", __func__, n_cbs));
-
- /* At most one can be currently executing; the rest we just
- * cancel... But we always make sure that the finalize callback
- * runs. */
- for (i = 0; i < n_cbs; ++i) {
- struct event_callback *evcb = evcbs[i];
- if (evcb == base->current_event) {
- event_callback_finalize_nolock_(base, 0, evcb, cb);
- ++n_pending;
- } else {
- event_callback_cancel_nolock_(base, evcb, 0);
- }
- }
-
- if (n_pending == 0) {
- /* Just do the first one. */
- event_callback_finalize_nolock_(base, 0, evcbs[0], cb);
- }
-
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- 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)
-{
- event_debug_assert_is_setup_(ev);
-
- 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(const struct event *ev, short event, struct timeval *tv)
-{
- int flags = 0;
-
- if (EVUTIL_FAILURE_CHECK(ev->ev_base == NULL)) {
- event_warnx("%s: event has no event_base set.", __func__);
- return 0;
- }
-
- EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
- event_debug_assert_is_setup_(ev);
-
- if (ev->ev_flags & EVLIST_INSERTED)
- flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL));
- if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
- flags |= ev->ev_res;
- if (ev->ev_flags & EVLIST_TIMEOUT)
- flags |= EV_TIMEOUT;
-
- event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL);
-
- /* See if there is a timeout that we should report */
- if (tv != NULL && (flags & event & EV_TIMEOUT)) {
- struct timeval tmp = ev->ev_timeout;
- tmp.tv_usec &= MICROSECONDS_MASK;
- /* correctly remamp to real time */
- evutil_timeradd(&ev->ev_base->tv_clock_diff, &tmp, tv);
- }
-
- EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
-
- return (flags & event);
-}
-
-int
-event_initialized(const struct event *ev)
-{
- if (!(ev->ev_flags & EVLIST_INIT))
- return 0;
-
- return 1;
-}
-
-void
-event_get_assignment(const struct event *event, struct event_base **base_out, evutil_socket_t *fd_out, short *events_out, event_callback_fn *callback_out, void **arg_out)
-{
- event_debug_assert_is_setup_(event);
-
- if (base_out)
- *base_out = event->ev_base;
- if (fd_out)
- *fd_out = event->ev_fd;
- if (events_out)
- *events_out = event->ev_events;
- if (callback_out)
- *callback_out = event->ev_callback;
- if (arg_out)
- *arg_out = event->ev_arg;
-}
-
-size_t
-event_get_struct_event_size(void)
-{
- return sizeof(struct event);
-}
-
-evutil_socket_t
-event_get_fd(const struct event *ev)
-{
- event_debug_assert_is_setup_(ev);
- return ev->ev_fd;
-}
-
-struct event_base *
-event_get_base(const struct event *ev)
-{
- event_debug_assert_is_setup_(ev);
- return ev->ev_base;
-}
-
-short
-event_get_events(const struct event *ev)
-{
- event_debug_assert_is_setup_(ev);
- return ev->ev_events;
-}
-
-event_callback_fn
-event_get_callback(const struct event *ev)
-{
- event_debug_assert_is_setup_(ev);
- return ev->ev_callback;
-}
-
-void *
-event_get_callback_arg(const struct event *ev)
-{
- event_debug_assert_is_setup_(ev);
- return ev->ev_arg;
-}
-
-int
-event_get_priority(const struct event *ev)
-{
- event_debug_assert_is_setup_(ev);
- return ev->ev_pri;
-}
-
-int
-event_add(struct event *ev, const struct timeval *tv)
-{
- int res;
-
- if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
- event_warnx("%s: event has no event_base set.", __func__);
- return -1;
- }
-
- EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
-
- res = event_add_nolock_(ev, tv, 0);
-
- EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
-
- return (res);
-}
-
-/* Helper callback: wake an event_base from another thread. This version
- * works by writing a byte to one end of a socketpair, so that the event_base
- * listening on the other end will wake up as the corresponding event
- * triggers */
-static int
-evthread_notify_base_default(struct event_base *base)
-{
- char buf[1];
- int r;
- buf[0] = (char) 0;
-#ifdef _WIN32
- r = send(base->th_notify_fd[1], buf, 1, 0);
-#else
- r = write(base->th_notify_fd[1], buf, 1);
-#endif
- return (r < 0 && ! EVUTIL_ERR_IS_EAGAIN(errno)) ? -1 : 0;
-}
-
-#ifdef EVENT__HAVE_EVENTFD
-/* Helper callback: wake an event_base from another thread. This version
- * assumes that you have a working eventfd() implementation. */
-static int
-evthread_notify_base_eventfd(struct event_base *base)
-{
- ev_uint64_t msg = 1;
- int r;
- do {
- r = write(base->th_notify_fd[0], (void*) &msg, sizeof(msg));
- } while (r < 0 && errno == EAGAIN);
-
- return (r < 0) ? -1 : 0;
-}
-#endif
-
-
-/** Tell the thread currently running the event_loop for base (if any) that it
- * needs to stop waiting in its dispatch function (if it is) and process all
- * active callbacks. */
-static int
-evthread_notify_base(struct event_base *base)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
- if (!base->th_notify_fn)
- return -1;
- if (base->is_notify_pending)
- return 0;
- base->is_notify_pending = 1;
- return base->th_notify_fn(base);
-}
-
-/* Implementation function to remove a timeout on a currently pending event.
- */
-int
-event_remove_timer_nolock_(struct event *ev)
-{
- struct event_base *base = ev->ev_base;
-
- EVENT_BASE_ASSERT_LOCKED(base);
- event_debug_assert_is_setup_(ev);
-
- event_debug(("event_remove_timer_nolock: event: %p", ev));
-
- /* If it's not pending on a timeout, we don't need to do anything. */
- if (ev->ev_flags & EVLIST_TIMEOUT) {
- event_queue_remove_timeout(base, ev);
- evutil_timerclear(&ev->ev_.ev_io.ev_timeout);
- }
-
- return (0);
-}
-
-int
-event_remove_timer(struct event *ev)
-{
- int res;
-
- if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
- event_warnx("%s: event has no event_base set.", __func__);
- return -1;
- }
-
- EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
-
- res = event_remove_timer_nolock_(ev);
-
- EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
-
- return (res);
-}
-
-/* Implementation function to add an event. Works just like event_add,
- * except: 1) it requires that we have the lock. 2) if tv_is_absolute is set,
- * we treat tv as an absolute time, not as an interval to add to the current
- * time */
-int
-event_add_nolock_(struct event *ev, const struct timeval *tv,
- int tv_is_absolute)
-{
- struct event_base *base = ev->ev_base;
- int res = 0;
- int notify = 0;
-
- EVENT_BASE_ASSERT_LOCKED(base);
- event_debug_assert_is_setup_(ev);
-
- event_debug((
- "event_add: event: %p (fd "EV_SOCK_FMT"), %s%s%s%scall %p",
- ev,
- EV_SOCK_ARG(ev->ev_fd),
- ev->ev_events & EV_READ ? "EV_READ " : " ",
- ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
- ev->ev_events & EV_CLOSED ? "EV_CLOSED " : " ",
- tv ? "EV_TIMEOUT " : " ",
- ev->ev_callback));
-
- EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
-
- if (ev->ev_flags & EVLIST_FINALIZING) {
- /* XXXX debug */
- return (-1);
- }
-
- /*
- * prepare for timeout insertion further below, if we get a
- * failure on any step, we should not change any state.
- */
- if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
- if (min_heap_reserve_(&base->timeheap,
- 1 + min_heap_size_(&base->timeheap)) == -1)
- return (-1); /* ENOMEM == errno */
- }
-
- /* If the main thread is currently executing a signal event's
- * callback, and we are not the main thread, then we want to wait
- * until the callback is done before we mess with the event, or else
- * we can race on ev_ncalls and ev_pncalls below. */
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (base->current_event == event_to_event_callback(ev) &&
- (ev->ev_events & EV_SIGNAL)
- && !EVBASE_IN_THREAD(base)) {
- ++base->current_event_waiters;
- EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
- }
-#endif
-
- if ((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED|EV_SIGNAL)) &&
- !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
- if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
- res = evmap_io_add_(base, ev->ev_fd, ev);
- else if (ev->ev_events & EV_SIGNAL)
- res = evmap_signal_add_(base, (int)ev->ev_fd, ev);
- if (res != -1)
- event_queue_insert_inserted(base, ev);
- if (res == 1) {
- /* evmap says we need to notify the main thread. */
- notify = 1;
- res = 0;
- }
- }
-
- /*
- * we should change the timeout state only if the previous event
- * addition succeeded.
- */
- if (res != -1 && tv != NULL) {
- struct timeval now;
- int common_timeout;
-#ifdef USE_REINSERT_TIMEOUT
- int was_common;
- int old_timeout_idx;
-#endif
-
- /*
- * for persistent timeout events, we remember the
- * timeout value and re-add the event.
- *
- * If tv_is_absolute, this was already set.
- */
- if (ev->ev_closure == EV_CLOSURE_EVENT_PERSIST && !tv_is_absolute)
- ev->ev_io_timeout = *tv;
-
-#ifndef USE_REINSERT_TIMEOUT
- if (ev->ev_flags & EVLIST_TIMEOUT) {
- event_queue_remove_timeout(base, ev);
- }
-#endif
-
- /* 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)) {
- if (ev->ev_events & EV_SIGNAL) {
- /* 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_active(base, event_to_event_callback(ev));
- }
-
- gettime(base, &now);
-
- common_timeout = is_common_timeout(tv, base);
-#ifdef USE_REINSERT_TIMEOUT
- was_common = is_common_timeout(&ev->ev_timeout, base);
- old_timeout_idx = COMMON_TIMEOUT_IDX(&ev->ev_timeout);
-#endif
-
- if (tv_is_absolute) {
- ev->ev_timeout = *tv;
- } else if (common_timeout) {
- struct timeval tmp = *tv;
- tmp.tv_usec &= MICROSECONDS_MASK;
- evutil_timeradd(&now, &tmp, &ev->ev_timeout);
- ev->ev_timeout.tv_usec |=
- (tv->tv_usec & ~MICROSECONDS_MASK);
- } else {
- evutil_timeradd(&now, tv, &ev->ev_timeout);
- }
-
- event_debug((
- "event_add: event %p, timeout in %d seconds %d useconds, call %p",
- ev, (int)tv->tv_sec, (int)tv->tv_usec, ev->ev_callback));
-
-#ifdef USE_REINSERT_TIMEOUT
- event_queue_reinsert_timeout(base, ev, was_common, common_timeout, old_timeout_idx);
-#else
- event_queue_insert_timeout(base, ev);
-#endif
-
- if (common_timeout) {
- struct common_timeout_list *ctl =
- get_common_timeout_list(base, &ev->ev_timeout);
- if (ev == TAILQ_FIRST(&ctl->events)) {
- common_timeout_schedule(ctl, &now, ev);
- }
- } else {
- struct event* top = NULL;
- /* See if the earliest timeout is now earlier than it
- * was before: if so, we will need to tell the main
- * thread to wake up earlier than it would otherwise.
- * We double check the timeout of the top element to
- * handle time distortions due to system suspension.
- */
- if (min_heap_elt_is_top_(ev))
- notify = 1;
- else if ((top = min_heap_top_(&base->timeheap)) != NULL &&
- evutil_timercmp(&top->ev_timeout, &now, <))
- notify = 1;
- }
- }
-
- /* if we are not in the right thread, we need to wake up the loop */
- if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
- evthread_notify_base(base);
-
- event_debug_note_add_(ev);
-
- return (res);
-}
-
-static int
-event_del_(struct event *ev, int blocking)
-{
- int res;
-
- if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
- event_warnx("%s: event has no event_base set.", __func__);
- return -1;
- }
-
- EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
-
- res = event_del_nolock_(ev, blocking);
-
- EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
-
- return (res);
-}
-
-int
-event_del(struct event *ev)
-{
- return event_del_(ev, EVENT_DEL_AUTOBLOCK);
-}
-
-int
-event_del_block(struct event *ev)
-{
- return event_del_(ev, EVENT_DEL_BLOCK);
-}
-
-int
-event_del_noblock(struct event *ev)
-{
- return event_del_(ev, EVENT_DEL_NOBLOCK);
-}
-
-/** Helper for event_del: always called with th_base_lock held.
- *
- * "blocking" must be one of the EVENT_DEL_{BLOCK, NOBLOCK, AUTOBLOCK,
- * EVEN_IF_FINALIZING} values. See those for more information.
- */
-int
-event_del_nolock_(struct event *ev, int blocking)
-{
- struct event_base *base;
- int res = 0, notify = 0;
-
- event_debug(("event_del: %p (fd "EV_SOCK_FMT"), callback %p",
- ev, EV_SOCK_ARG(ev->ev_fd), ev->ev_callback));
-
- /* An event without a base has not been added */
- if (ev->ev_base == NULL)
- return (-1);
-
- EVENT_BASE_ASSERT_LOCKED(ev->ev_base);
-
- if (blocking != EVENT_DEL_EVEN_IF_FINALIZING) {
- if (ev->ev_flags & EVLIST_FINALIZING) {
- /* XXXX Debug */
- return 0;
- }
- }
-
- /* If the main thread is currently executing this event's callback,
- * and we are not the main thread, then we want to wait until the
- * callback is done before we start removing the event. That way,
- * when this function returns, it will be safe to free the
- * user-supplied argument. */
- base = ev->ev_base;
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (blocking != EVENT_DEL_NOBLOCK &&
- base->current_event == event_to_event_callback(ev) &&
- !EVBASE_IN_THREAD(base) &&
- (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) {
- ++base->current_event_waiters;
- EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
- }
-#endif
-
- EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));
-
- /* See if we are just active executing this event in a loop */
- if (ev->ev_events & EV_SIGNAL) {
- if (ev->ev_ncalls && ev->ev_pncalls) {
- /* Abort loop */
- *ev->ev_pncalls = 0;
- }
- }
-
- if (ev->ev_flags & EVLIST_TIMEOUT) {
- /* NOTE: We never need to notify the main thread because of a
- * deleted timeout event: all that could happen if we don't is
- * that the dispatch loop might wake up too early. But the
- * point of notifying the main thread _is_ to wake up the
- * dispatch loop early anyway, so we wouldn't gain anything by
- * doing it.
- */
- event_queue_remove_timeout(base, ev);
- }
-
- if (ev->ev_flags & EVLIST_ACTIVE)
- event_queue_remove_active(base, event_to_event_callback(ev));
- else if (ev->ev_flags & EVLIST_ACTIVE_LATER)
- event_queue_remove_active_later(base, event_to_event_callback(ev));
-
- if (ev->ev_flags & EVLIST_INSERTED) {
- event_queue_remove_inserted(base, ev);
- if (ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))
- res = evmap_io_del_(base, ev->ev_fd, ev);
- else
- res = evmap_signal_del_(base, (int)ev->ev_fd, ev);
- if (res == 1) {
- /* evmap says we need to notify the main thread. */
- notify = 1;
- res = 0;
- }
- }
-
- /* if we are not in the right thread, we need to wake up the loop */
- if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
- evthread_notify_base(base);
-
- event_debug_note_del_(ev);
-
- return (res);
-}
-
-void
-event_active(struct event *ev, int res, short ncalls)
-{
- if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
- event_warnx("%s: event has no event_base set.", __func__);
- return;
- }
-
- EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
-
- event_debug_assert_is_setup_(ev);
-
- event_active_nolock_(ev, res, ncalls);
-
- EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
-}
-
-
-void
-event_active_nolock_(struct event *ev, int res, short ncalls)
-{
- struct event_base *base;
-
- event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p",
- ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback));
-
- base = ev->ev_base;
- EVENT_BASE_ASSERT_LOCKED(base);
-
- if (ev->ev_flags & EVLIST_FINALIZING) {
- /* XXXX debug */
- return;
- }
-
- switch ((ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
- default:
- case EVLIST_ACTIVE|EVLIST_ACTIVE_LATER:
- EVUTIL_ASSERT(0);
- break;
- case EVLIST_ACTIVE:
- /* We get different kinds of events, add them together */
- ev->ev_res |= res;
- return;
- case EVLIST_ACTIVE_LATER:
- ev->ev_res |= res;
- break;
- case 0:
- ev->ev_res = res;
- break;
- }
-
- if (ev->ev_pri < base->event_running_priority)
- base->event_continue = 1;
-
- if (ev->ev_events & EV_SIGNAL) {
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (base->current_event == event_to_event_callback(ev) &&
- !EVBASE_IN_THREAD(base)) {
- ++base->current_event_waiters;
- EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
- }
-#endif
- ev->ev_ncalls = ncalls;
- ev->ev_pncalls = NULL;
- }
-
- event_callback_activate_nolock_(base, event_to_event_callback(ev));
-}
-
-void
-event_active_later_(struct event *ev, int res)
-{
- EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
- event_active_later_nolock_(ev, res);
- EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
-}
-
-void
-event_active_later_nolock_(struct event *ev, int res)
-{
- struct event_base *base = ev->ev_base;
- EVENT_BASE_ASSERT_LOCKED(base);
-
- if (ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) {
- /* We get different kinds of events, add them together */
- ev->ev_res |= res;
- return;
- }
-
- ev->ev_res = res;
-
- event_callback_activate_later_nolock_(base, event_to_event_callback(ev));
-}
-
-int
-event_callback_activate_(struct event_base *base,
- struct event_callback *evcb)
-{
- int r;
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- r = event_callback_activate_nolock_(base, evcb);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-int
-event_callback_activate_nolock_(struct event_base *base,
- struct event_callback *evcb)
-{
- int r = 1;
-
- if (evcb->evcb_flags & EVLIST_FINALIZING)
- return 0;
-
- switch (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) {
- default:
- EVUTIL_ASSERT(0);
- case EVLIST_ACTIVE_LATER:
- event_queue_remove_active_later(base, evcb);
- r = 0;
- break;
- case EVLIST_ACTIVE:
- return 0;
- case 0:
- break;
- }
-
- event_queue_insert_active(base, evcb);
-
- if (EVBASE_NEED_NOTIFY(base))
- evthread_notify_base(base);
-
- return r;
-}
-
-int
-event_callback_activate_later_nolock_(struct event_base *base,
- struct event_callback *evcb)
-{
- if (evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))
- return 0;
-
- event_queue_insert_active_later(base, evcb);
- if (EVBASE_NEED_NOTIFY(base))
- evthread_notify_base(base);
- return 1;
-}
-
-void
-event_callback_init_(struct event_base *base,
- struct event_callback *cb)
-{
- memset(cb, 0, sizeof(*cb));
- cb->evcb_pri = base->nactivequeues - 1;
-}
-
-int
-event_callback_cancel_(struct event_base *base,
- struct event_callback *evcb)
-{
- int r;
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- r = event_callback_cancel_nolock_(base, evcb, 0);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-int
-event_callback_cancel_nolock_(struct event_base *base,
- struct event_callback *evcb, int even_if_finalizing)
-{
- if ((evcb->evcb_flags & EVLIST_FINALIZING) && !even_if_finalizing)
- return 0;
-
- if (evcb->evcb_flags & EVLIST_INIT)
- return event_del_nolock_(event_callback_to_event(evcb),
- even_if_finalizing ? EVENT_DEL_EVEN_IF_FINALIZING : EVENT_DEL_AUTOBLOCK);
-
- switch ((evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER))) {
- default:
- case EVLIST_ACTIVE|EVLIST_ACTIVE_LATER:
- EVUTIL_ASSERT(0);
- break;
- case EVLIST_ACTIVE:
- /* We get different kinds of events, add them together */
- event_queue_remove_active(base, evcb);
- return 0;
- case EVLIST_ACTIVE_LATER:
- event_queue_remove_active_later(base, evcb);
- break;
- case 0:
- break;
- }
-
- return 0;
-}
-
-void
-event_deferred_cb_init_(struct event_callback *cb, ev_uint8_t priority, deferred_cb_fn fn, void *arg)
-{
- memset(cb, 0, sizeof(*cb));
- cb->evcb_cb_union.evcb_selfcb = fn;
- cb->evcb_arg = arg;
- cb->evcb_pri = priority;
- cb->evcb_closure = EV_CLOSURE_CB_SELF;
-}
-
-void
-event_deferred_cb_set_priority_(struct event_callback *cb, ev_uint8_t priority)
-{
- cb->evcb_pri = priority;
-}
-
-void
-event_deferred_cb_cancel_(struct event_base *base, struct event_callback *cb)
-{
- if (!base)
- base = current_base;
- event_callback_cancel_(base, cb);
-}
-
-#define MAX_DEFERREDS_QUEUED 32
-int
-event_deferred_cb_schedule_(struct event_base *base, struct event_callback *cb)
-{
- int r = 1;
- if (!base)
- base = current_base;
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- if (base->n_deferreds_queued > MAX_DEFERREDS_QUEUED) {
- r = event_callback_activate_later_nolock_(base, cb);
- } else {
- r = event_callback_activate_nolock_(base, cb);
- if (r) {
- ++base->n_deferreds_queued;
- }
- }
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-static int
-timeout_next(struct event_base *base, struct timeval **tv_p)
-{
- /* Caller must hold th_base_lock */
- struct timeval now;
- struct event *ev;
- struct timeval *tv = *tv_p;
- int res = 0;
-
- ev = min_heap_top_(&base->timeheap);
-
- if (ev == NULL) {
- /* if no time-based events are active wait for I/O */
- *tv_p = NULL;
- goto out;
- }
-
- if (gettime(base, &now) == -1) {
- res = -1;
- goto out;
- }
-
- if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
- evutil_timerclear(tv);
- goto out;
- }
-
- evutil_timersub(&ev->ev_timeout, &now, tv);
-
- EVUTIL_ASSERT(tv->tv_sec >= 0);
- EVUTIL_ASSERT(tv->tv_usec >= 0);
- event_debug(("timeout_next: event: %p, in %d seconds, %d useconds", ev, (int)tv->tv_sec, (int)tv->tv_usec));
-
-out:
- return (res);
-}
-
-/* Activate every event whose timeout has elapsed. */
-static void
-timeout_process(struct event_base *base)
-{
- /* Caller must hold lock. */
- struct timeval now;
- struct event *ev;
-
- if (min_heap_empty_(&base->timeheap)) {
- return;
- }
-
- gettime(base, &now);
-
- while ((ev = min_heap_top_(&base->timeheap))) {
- if (evutil_timercmp(&ev->ev_timeout, &now, >))
- break;
-
- /* delete this event from the I/O queues */
- event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
-
- event_debug(("timeout_process: event: %p, call %p",
- ev, ev->ev_callback));
- event_active_nolock_(ev, EV_TIMEOUT, 1);
- }
-}
-
-#if (EVLIST_INTERNAL >> 4) != 1
-#error "Mismatch for value of EVLIST_INTERNAL"
-#endif
-
-#ifndef MAX
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#endif
-
-#define MAX_EVENT_COUNT(var, v) var = MAX(var, v)
-
-/* These are a fancy way to spell
- if (flags & EVLIST_INTERNAL)
- base->event_count--/++;
-*/
-#define DECR_EVENT_COUNT(base,flags) \
- ((base)->event_count -= (~((flags) >> 4) & 1))
-#define INCR_EVENT_COUNT(base,flags) do { \
- ((base)->event_count += (~((flags) >> 4) & 1)); \
- MAX_EVENT_COUNT((base)->event_count_max, (base)->event_count); \
-} while (0)
-
-static void
-event_queue_remove_inserted(struct event_base *base, struct event *ev)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
- if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_INSERTED))) {
- event_errx(1, "%s: %p(fd "EV_SOCK_FMT") not on queue %x", __func__,
- ev, EV_SOCK_ARG(ev->ev_fd), EVLIST_INSERTED);
- return;
- }
- DECR_EVENT_COUNT(base, ev->ev_flags);
- ev->ev_flags &= ~EVLIST_INSERTED;
-}
-static void
-event_queue_remove_active(struct event_base *base, struct event_callback *evcb)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
- if (EVUTIL_FAILURE_CHECK(!(evcb->evcb_flags & EVLIST_ACTIVE))) {
- event_errx(1, "%s: %p not on queue %x", __func__,
- evcb, EVLIST_ACTIVE);
- return;
- }
- DECR_EVENT_COUNT(base, evcb->evcb_flags);
- evcb->evcb_flags &= ~EVLIST_ACTIVE;
- base->event_count_active--;
-
- TAILQ_REMOVE(&base->activequeues[evcb->evcb_pri],
- evcb, evcb_active_next);
-}
-static void
-event_queue_remove_active_later(struct event_base *base, struct event_callback *evcb)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
- if (EVUTIL_FAILURE_CHECK(!(evcb->evcb_flags & EVLIST_ACTIVE_LATER))) {
- event_errx(1, "%s: %p not on queue %x", __func__,
- evcb, EVLIST_ACTIVE_LATER);
- return;
- }
- DECR_EVENT_COUNT(base, evcb->evcb_flags);
- evcb->evcb_flags &= ~EVLIST_ACTIVE_LATER;
- base->event_count_active--;
-
- TAILQ_REMOVE(&base->active_later_queue, evcb, evcb_active_next);
-}
-static void
-event_queue_remove_timeout(struct event_base *base, struct event *ev)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
- if (EVUTIL_FAILURE_CHECK(!(ev->ev_flags & EVLIST_TIMEOUT))) {
- event_errx(1, "%s: %p(fd "EV_SOCK_FMT") not on queue %x", __func__,
- ev, EV_SOCK_ARG(ev->ev_fd), EVLIST_TIMEOUT);
- return;
- }
- DECR_EVENT_COUNT(base, ev->ev_flags);
- ev->ev_flags &= ~EVLIST_TIMEOUT;
-
- if (is_common_timeout(&ev->ev_timeout, base)) {
- struct common_timeout_list *ctl =
- get_common_timeout_list(base, &ev->ev_timeout);
- TAILQ_REMOVE(&ctl->events, ev,
- ev_timeout_pos.ev_next_with_common_timeout);
- } else {
- min_heap_erase_(&base->timeheap, ev);
- }
-}
-
-#ifdef USE_REINSERT_TIMEOUT
-/* Remove and reinsert 'ev' into the timeout queue. */
-static void
-event_queue_reinsert_timeout(struct event_base *base, struct event *ev,
- int was_common, int is_common, int old_timeout_idx)
-{
- struct common_timeout_list *ctl;
- if (!(ev->ev_flags & EVLIST_TIMEOUT)) {
- event_queue_insert_timeout(base, ev);
- return;
- }
-
- switch ((was_common<<1) | is_common) {
- case 3: /* Changing from one common timeout to another */
- ctl = base->common_timeout_queues[old_timeout_idx];
- TAILQ_REMOVE(&ctl->events, ev,
- ev_timeout_pos.ev_next_with_common_timeout);
- ctl = get_common_timeout_list(base, &ev->ev_timeout);
- insert_common_timeout_inorder(ctl, ev);
- break;
- case 2: /* Was common; is no longer common */
- ctl = base->common_timeout_queues[old_timeout_idx];
- TAILQ_REMOVE(&ctl->events, ev,
- ev_timeout_pos.ev_next_with_common_timeout);
- min_heap_push_(&base->timeheap, ev);
- break;
- case 1: /* Wasn't common; has become common. */
- min_heap_erase_(&base->timeheap, ev);
- ctl = get_common_timeout_list(base, &ev->ev_timeout);
- insert_common_timeout_inorder(ctl, ev);
- break;
- case 0: /* was in heap; is still on heap. */
- min_heap_adjust_(&base->timeheap, ev);
- break;
- default:
- EVUTIL_ASSERT(0); /* unreachable */
- break;
- }
-}
-#endif
-
-/* Add 'ev' to the common timeout list in 'ev'. */
-static void
-insert_common_timeout_inorder(struct common_timeout_list *ctl,
- struct event *ev)
-{
- struct event *e;
- /* By all logic, we should just be able to append 'ev' to the end of
- * ctl->events, since the timeout on each 'ev' is set to {the common
- * timeout} + {the time when we add the event}, and so the events
- * should arrive in order of their timeeouts. But just in case
- * there's some wacky threading issue going on, we do a search from
- * the end of 'ev' to find the right insertion point.
- */
- TAILQ_FOREACH_REVERSE(e, &ctl->events,
- event_list, ev_timeout_pos.ev_next_with_common_timeout) {
- /* This timercmp is a little sneaky, since both ev and e have
- * magic values in tv_usec. Fortunately, they ought to have
- * the _same_ magic values in tv_usec. Let's assert for that.
- */
- EVUTIL_ASSERT(
- is_same_common_timeout(&e->ev_timeout, &ev->ev_timeout));
- if (evutil_timercmp(&ev->ev_timeout, &e->ev_timeout, >=)) {
- TAILQ_INSERT_AFTER(&ctl->events, e, ev,
- ev_timeout_pos.ev_next_with_common_timeout);
- return;
- }
- }
- TAILQ_INSERT_HEAD(&ctl->events, ev,
- ev_timeout_pos.ev_next_with_common_timeout);
-}
-
-static void
-event_queue_insert_inserted(struct event_base *base, struct event *ev)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
-
- if (EVUTIL_FAILURE_CHECK(ev->ev_flags & EVLIST_INSERTED)) {
- event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already inserted", __func__,
- ev, EV_SOCK_ARG(ev->ev_fd));
- return;
- }
-
- INCR_EVENT_COUNT(base, ev->ev_flags);
-
- ev->ev_flags |= EVLIST_INSERTED;
-}
-
-static void
-event_queue_insert_active(struct event_base *base, struct event_callback *evcb)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
-
- if (evcb->evcb_flags & EVLIST_ACTIVE) {
- /* Double insertion is possible for active events */
- return;
- }
-
- INCR_EVENT_COUNT(base, evcb->evcb_flags);
-
- evcb->evcb_flags |= EVLIST_ACTIVE;
-
- base->event_count_active++;
- MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
- EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
- TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri],
- evcb, evcb_active_next);
-}
-
-static void
-event_queue_insert_active_later(struct event_base *base, struct event_callback *evcb)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
- if (evcb->evcb_flags & (EVLIST_ACTIVE_LATER|EVLIST_ACTIVE)) {
- /* Double insertion is possible */
- return;
- }
-
- INCR_EVENT_COUNT(base, evcb->evcb_flags);
- evcb->evcb_flags |= EVLIST_ACTIVE_LATER;
- base->event_count_active++;
- MAX_EVENT_COUNT(base->event_count_active_max, base->event_count_active);
- EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
- TAILQ_INSERT_TAIL(&base->active_later_queue, evcb, evcb_active_next);
-}
-
-static void
-event_queue_insert_timeout(struct event_base *base, struct event *ev)
-{
- EVENT_BASE_ASSERT_LOCKED(base);
-
- if (EVUTIL_FAILURE_CHECK(ev->ev_flags & EVLIST_TIMEOUT)) {
- event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already on timeout", __func__,
- ev, EV_SOCK_ARG(ev->ev_fd));
- return;
- }
-
- INCR_EVENT_COUNT(base, ev->ev_flags);
-
- ev->ev_flags |= EVLIST_TIMEOUT;
-
- if (is_common_timeout(&ev->ev_timeout, base)) {
- struct common_timeout_list *ctl =
- get_common_timeout_list(base, &ev->ev_timeout);
- insert_common_timeout_inorder(ctl, ev);
- } else {
- min_heap_push_(&base->timeheap, ev);
- }
-}
-
-static void
-event_queue_make_later_events_active(struct event_base *base)
-{
- struct event_callback *evcb;
- EVENT_BASE_ASSERT_LOCKED(base);
-
- while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
- TAILQ_REMOVE(&base->active_later_queue, evcb, evcb_active_next);
- evcb->evcb_flags = (evcb->evcb_flags & ~EVLIST_ACTIVE_LATER) | EVLIST_ACTIVE;
- EVUTIL_ASSERT(evcb->evcb_pri < base->nactivequeues);
- TAILQ_INSERT_TAIL(&base->activequeues[evcb->evcb_pri], evcb, evcb_active_next);
- base->n_deferreds_queued += (evcb->evcb_closure == EV_CLOSURE_CB_SELF);
- }
-}
-
-/* Functions for debugging */
-
-const char *
-event_get_version(void)
-{
- return (EVENT__VERSION);
-}
-
-ev_uint32_t
-event_get_version_number(void)
-{
- return (EVENT__NUMERIC_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);
-}
-
-#ifndef EVENT__DISABLE_MM_REPLACEMENT
-static void *(*mm_malloc_fn_)(size_t sz) = NULL;
-static void *(*mm_realloc_fn_)(void *p, size_t sz) = NULL;
-static void (*mm_free_fn_)(void *p) = NULL;
-
-void *
-event_mm_malloc_(size_t sz)
-{
- if (sz == 0)
- return NULL;
-
- if (mm_malloc_fn_)
- return mm_malloc_fn_(sz);
- else
- return malloc(sz);
-}
-
-void *
-event_mm_calloc_(size_t count, size_t size)
-{
- if (count == 0 || size == 0)
- return NULL;
-
- if (mm_malloc_fn_) {
- size_t sz = count * size;
- void *p = NULL;
- if (count > EV_SIZE_MAX / size)
- goto error;
- p = mm_malloc_fn_(sz);
- if (p)
- return memset(p, 0, sz);
- } else {
- void *p = calloc(count, size);
-#ifdef _WIN32
- /* Windows calloc doesn't reliably set ENOMEM */
- if (p == NULL)
- goto error;
-#endif
- return p;
- }
-
-error:
- errno = ENOMEM;
- return NULL;
-}
-
-char *
-event_mm_strdup_(const char *str)
-{
- if (!str) {
- errno = EINVAL;
- return NULL;
- }
-
- if (mm_malloc_fn_) {
- size_t ln = strlen(str);
- void *p = NULL;
- if (ln == EV_SIZE_MAX)
- goto error;
- p = mm_malloc_fn_(ln+1);
- if (p)
- return memcpy(p, str, ln+1);
- } else
-#ifdef _WIN32
- return _strdup(str);
-#else
- return strdup(str);
-#endif
-
-error:
- errno = ENOMEM;
- return NULL;
-}
-
-void *
-event_mm_realloc_(void *ptr, size_t sz)
-{
- if (mm_realloc_fn_)
- return mm_realloc_fn_(ptr, sz);
- else
- return realloc(ptr, sz);
-}
-
-void
-event_mm_free_(void *ptr)
-{
- if (mm_free_fn_)
- mm_free_fn_(ptr);
- else
- free(ptr);
-}
-
-void
-event_set_mem_functions(void *(*malloc_fn)(size_t sz),
- void *(*realloc_fn)(void *ptr, size_t sz),
- void (*free_fn)(void *ptr))
-{
- mm_malloc_fn_ = malloc_fn;
- mm_realloc_fn_ = realloc_fn;
- mm_free_fn_ = free_fn;
-}
-#endif
-
-#ifdef EVENT__HAVE_EVENTFD
-static void
-evthread_notify_drain_eventfd(evutil_socket_t fd, short what, void *arg)
-{
- ev_uint64_t msg;
- ev_ssize_t r;
- struct event_base *base = arg;
-
- r = read(fd, (void*) &msg, sizeof(msg));
- if (r<0 && errno != EAGAIN) {
- event_sock_warn(fd, "Error reading from eventfd");
- }
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- base->is_notify_pending = 0;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-#endif
-
-static void
-evthread_notify_drain_default(evutil_socket_t fd, short what, void *arg)
-{
- unsigned char buf[1024];
- struct event_base *base = arg;
-#ifdef _WIN32
- while (recv(fd, (char*)buf, sizeof(buf), 0) > 0)
- ;
-#else
- while (read(fd, (char*)buf, sizeof(buf)) > 0)
- ;
-#endif
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- base->is_notify_pending = 0;
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-int
-evthread_make_base_notifiable(struct event_base *base)
-{
- int r;
- if (!base)
- return -1;
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- r = evthread_make_base_notifiable_nolock_(base);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-static int
-evthread_make_base_notifiable_nolock_(struct event_base *base)
-{
- void (*cb)(evutil_socket_t, short, void *);
- int (*notify)(struct event_base *);
-
- if (base->th_notify_fn != NULL) {
- /* The base is already notifiable: we're doing fine. */
- return 0;
- }
-
-#if defined(EVENT__HAVE_WORKING_KQUEUE)
- if (base->evsel == &kqops && event_kq_add_notify_event_(base) == 0) {
- base->th_notify_fn = event_kq_notify_base_;
- /* No need to add an event here; the backend can wake
- * itself up just fine. */
- return 0;
- }
-#endif
-
-#ifdef EVENT__HAVE_EVENTFD
- base->th_notify_fd[0] = evutil_eventfd_(0,
- EVUTIL_EFD_CLOEXEC|EVUTIL_EFD_NONBLOCK);
- if (base->th_notify_fd[0] >= 0) {
- base->th_notify_fd[1] = -1;
- notify = evthread_notify_base_eventfd;
- cb = evthread_notify_drain_eventfd;
- } else
-#endif
- if (evutil_make_internal_pipe_(base->th_notify_fd) == 0) {
- notify = evthread_notify_base_default;
- cb = evthread_notify_drain_default;
- } else {
- return -1;
- }
-
- base->th_notify_fn = notify;
-
- /* prepare an event that we can use for wakeup */
- event_assign(&base->th_notify, base, base->th_notify_fd[0],
- EV_READ|EV_PERSIST, cb, base);
-
- /* we need to mark this as internal event */
- base->th_notify.ev_flags |= EVLIST_INTERNAL;
- event_priority_set(&base->th_notify, 0);
-
- return event_add_nolock_(&base->th_notify, NULL, 0);
-}
-
-int
-event_base_foreach_event_nolock_(struct event_base *base,
- event_base_foreach_event_cb fn, void *arg)
-{
- int r, i;
- unsigned u;
- struct event *ev;
-
- /* Start out with all the EVLIST_INSERTED events. */
- if ((r = evmap_foreach_event_(base, fn, arg)))
- return r;
-
- /* Okay, now we deal with those events that have timeouts and are in
- * the min-heap. */
- for (u = 0; u < base->timeheap.n; ++u) {
- ev = base->timeheap.p[u];
- if (ev->ev_flags & EVLIST_INSERTED) {
- /* we already processed this one */
- continue;
- }
- if ((r = fn(base, ev, arg)))
- return r;
- }
-
- /* Now for the events in one of the timeout queues.
- * the min-heap. */
- for (i = 0; i < base->n_common_timeouts; ++i) {
- struct common_timeout_list *ctl =
- base->common_timeout_queues[i];
- TAILQ_FOREACH(ev, &ctl->events,
- ev_timeout_pos.ev_next_with_common_timeout) {
- if (ev->ev_flags & EVLIST_INSERTED) {
- /* we already processed this one */
- continue;
- }
- if ((r = fn(base, ev, arg)))
- return r;
- }
- }
-
- /* Finally, we deal wit all the active events that we haven't touched
- * yet. */
- for (i = 0; i < base->nactivequeues; ++i) {
- struct event_callback *evcb;
- TAILQ_FOREACH(evcb, &base->activequeues[i], evcb_active_next) {
- if ((evcb->evcb_flags & (EVLIST_INIT|EVLIST_INSERTED|EVLIST_TIMEOUT)) != EVLIST_INIT) {
- /* This isn't an event (evlist_init clear), or
- * we already processed it. (inserted or
- * timeout set */
- continue;
- }
- ev = event_callback_to_event(evcb);
- if ((r = fn(base, ev, arg)))
- return r;
- }
- }
-
- return 0;
-}
-
-/* Helper for event_base_dump_events: called on each event in the event base;
- * dumps only the inserted events. */
-static int
-dump_inserted_event_fn(const struct event_base *base, const struct event *e, void *arg)
-{
- FILE *output = arg;
- const char *gloss = (e->ev_events & EV_SIGNAL) ?
- "sig" : "fd ";
-
- if (! (e->ev_flags & (EVLIST_INSERTED|EVLIST_TIMEOUT)))
- return 0;
-
- fprintf(output, " %p [%s "EV_SOCK_FMT"]%s%s%s%s%s%s",
- (void*)e, gloss, EV_SOCK_ARG(e->ev_fd),
- (e->ev_events&EV_READ)?" Read":"",
- (e->ev_events&EV_WRITE)?" Write":"",
- (e->ev_events&EV_CLOSED)?" EOF":"",
- (e->ev_events&EV_SIGNAL)?" Signal":"",
- (e->ev_events&EV_PERSIST)?" Persist":"",
- (e->ev_flags&EVLIST_INTERNAL)?" Internal":"");
- if (e->ev_flags & EVLIST_TIMEOUT) {
- struct timeval tv;
- tv.tv_sec = e->ev_timeout.tv_sec;
- tv.tv_usec = e->ev_timeout.tv_usec & MICROSECONDS_MASK;
- evutil_timeradd(&tv, &base->tv_clock_diff, &tv);
- fprintf(output, " Timeout=%ld.%06d",
- (long)tv.tv_sec, (int)(tv.tv_usec & MICROSECONDS_MASK));
- }
- fputc('\n', output);
-
- return 0;
-}
-
-/* Helper for event_base_dump_events: called on each event in the event base;
- * dumps only the active events. */
-static int
-dump_active_event_fn(const struct event_base *base, const struct event *e, void *arg)
-{
- FILE *output = arg;
- const char *gloss = (e->ev_events & EV_SIGNAL) ?
- "sig" : "fd ";
-
- if (! (e->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)))
- return 0;
-
- fprintf(output, " %p [%s "EV_SOCK_FMT", priority=%d]%s%s%s%s%s active%s%s\n",
- (void*)e, gloss, EV_SOCK_ARG(e->ev_fd), e->ev_pri,
- (e->ev_res&EV_READ)?" Read":"",
- (e->ev_res&EV_WRITE)?" Write":"",
- (e->ev_res&EV_CLOSED)?" EOF":"",
- (e->ev_res&EV_SIGNAL)?" Signal":"",
- (e->ev_res&EV_TIMEOUT)?" Timeout":"",
- (e->ev_flags&EVLIST_INTERNAL)?" [Internal]":"",
- (e->ev_flags&EVLIST_ACTIVE_LATER)?" [NextTime]":"");
-
- return 0;
-}
-
-int
-event_base_foreach_event(struct event_base *base,
- event_base_foreach_event_cb fn, void *arg)
-{
- int r;
- if ((!fn) || (!base)) {
- return -1;
- }
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- r = event_base_foreach_event_nolock_(base, fn, arg);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
- return r;
-}
-
-
-void
-event_base_dump_events(struct event_base *base, FILE *output)
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- fprintf(output, "Inserted events:\n");
- event_base_foreach_event_nolock_(base, dump_inserted_event_fn, output);
-
- fprintf(output, "Active events:\n");
- event_base_foreach_event_nolock_(base, dump_active_event_fn, output);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-void
-event_base_active_by_fd(struct event_base *base, evutil_socket_t fd, short events)
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- evmap_io_active_(base, fd, events & (EV_READ|EV_WRITE|EV_CLOSED));
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-void
-event_base_active_by_signal(struct event_base *base, int sig)
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- evmap_signal_active_(base, sig, 1);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-
-void
-event_base_add_virtual_(struct event_base *base)
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- base->virtual_event_count++;
- MAX_EVENT_COUNT(base->virtual_event_count_max, base->virtual_event_count);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-void
-event_base_del_virtual_(struct event_base *base)
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- EVUTIL_ASSERT(base->virtual_event_count > 0);
- base->virtual_event_count--;
- if (base->virtual_event_count == 0 && EVBASE_NEED_NOTIFY(base))
- evthread_notify_base(base);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-static void
-event_free_debug_globals_locks(void)
-{
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-#ifndef EVENT__DISABLE_DEBUG_MODE
- if (event_debug_map_lock_ != NULL) {
- EVTHREAD_FREE_LOCK(event_debug_map_lock_, 0);
- event_debug_map_lock_ = NULL;
- evthreadimpl_disable_lock_debugging_();
- }
-#endif /* EVENT__DISABLE_DEBUG_MODE */
-#endif /* EVENT__DISABLE_THREAD_SUPPORT */
- return;
-}
-
-static void
-event_free_debug_globals(void)
-{
- event_free_debug_globals_locks();
-}
-
-static void
-event_free_evsig_globals(void)
-{
- evsig_free_globals_();
-}
-
-static void
-event_free_evutil_globals(void)
-{
- evutil_free_globals_();
-}
-
-static void
-event_free_globals(void)
-{
- event_free_debug_globals();
- event_free_evsig_globals();
- event_free_evutil_globals();
-}
-
-void
-libevent_global_shutdown(void)
-{
- event_disable_debug_mode();
- event_free_globals();
-}
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-int
-event_global_setup_locks_(const int enable_locks)
-{
-#ifndef EVENT__DISABLE_DEBUG_MODE
- EVTHREAD_SETUP_GLOBAL_LOCK(event_debug_map_lock_, 0);
-#endif
- if (evsig_global_setup_locks_(enable_locks) < 0)
- return -1;
- if (evutil_global_setup_locks_(enable_locks) < 0)
- return -1;
- if (evutil_secure_rng_global_setup_locks_(enable_locks) < 0)
- return -1;
- return 0;
-}
-#endif
-
-void
-event_base_assert_ok_(struct event_base *base)
-{
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- event_base_assert_ok_nolock_(base);
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-void
-event_base_assert_ok_nolock_(struct event_base *base)
-{
- int i;
- int count;
-
- /* First do checks on the per-fd and per-signal lists */
- evmap_check_integrity_(base);
-
- /* Check the heap property */
- for (i = 1; i < (int)base->timeheap.n; ++i) {
- int parent = (i - 1) / 2;
- struct event *ev, *p_ev;
- ev = base->timeheap.p[i];
- p_ev = base->timeheap.p[parent];
- EVUTIL_ASSERT(ev->ev_flags & EVLIST_TIMEOUT);
- EVUTIL_ASSERT(evutil_timercmp(&p_ev->ev_timeout, &ev->ev_timeout, <=));
- EVUTIL_ASSERT(ev->ev_timeout_pos.min_heap_idx == i);
- }
-
- /* Check that the common timeouts are fine */
- for (i = 0; i < base->n_common_timeouts; ++i) {
- struct common_timeout_list *ctl = base->common_timeout_queues[i];
- struct event *last=NULL, *ev;
-
- EVUTIL_ASSERT_TAILQ_OK(&ctl->events, event, ev_timeout_pos.ev_next_with_common_timeout);
-
- TAILQ_FOREACH(ev, &ctl->events, ev_timeout_pos.ev_next_with_common_timeout) {
- if (last)
- EVUTIL_ASSERT(evutil_timercmp(&last->ev_timeout, &ev->ev_timeout, <=));
- EVUTIL_ASSERT(ev->ev_flags & EVLIST_TIMEOUT);
- EVUTIL_ASSERT(is_common_timeout(&ev->ev_timeout,base));
- EVUTIL_ASSERT(COMMON_TIMEOUT_IDX(&ev->ev_timeout) == i);
- last = ev;
- }
- }
-
- /* Check the active queues. */
- count = 0;
- for (i = 0; i < base->nactivequeues; ++i) {
- struct event_callback *evcb;
- EVUTIL_ASSERT_TAILQ_OK(&base->activequeues[i], event_callback, evcb_active_next);
- TAILQ_FOREACH(evcb, &base->activequeues[i], evcb_active_next) {
- EVUTIL_ASSERT((evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) == EVLIST_ACTIVE);
- EVUTIL_ASSERT(evcb->evcb_pri == i);
- ++count;
- }
- }
-
- {
- struct event_callback *evcb;
- TAILQ_FOREACH(evcb, &base->active_later_queue, evcb_active_next) {
- EVUTIL_ASSERT((evcb->evcb_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER)) == EVLIST_ACTIVE_LATER);
- ++count;
- }
- }
- EVUTIL_ASSERT(count == base->event_count_active);
-}
diff --git a/libs/libevent/src/event_iocp.c b/libs/libevent/src/event_iocp.c
deleted file mode 100644
index a9902fbc42..0000000000
--- a/libs/libevent/src/event_iocp.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "evconfig-private.h"
-
-#ifndef _WIN32_WINNT
-/* Minimum required for InitializeCriticalSectionAndSpinCount */
-#define _WIN32_WINNT 0x0403
-#endif
-#include <winsock2.h>
-#include <windows.h>
-#include <process.h>
-#include <stdio.h>
-#include <mswsock.h>
-
-#include "event2/util.h"
-#include "util-internal.h"
-#include "iocp-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "event-internal.h"
-#include "evthread-internal.h"
-
-#define NOTIFICATION_KEY ((ULONG_PTR)-1)
-
-void
-event_overlapped_init_(struct event_overlapped *o, iocp_callback cb)
-{
- memset(o, 0, sizeof(struct event_overlapped));
- o->cb = cb;
-}
-
-static void
-handle_entry(OVERLAPPED *o, ULONG_PTR completion_key, DWORD nBytes, int ok)
-{
- struct event_overlapped *eo =
- EVUTIL_UPCAST(o, struct event_overlapped, overlapped);
- eo->cb(eo, completion_key, nBytes, ok);
-}
-
-static void
-loop(void *port_)
-{
- struct event_iocp_port *port = port_;
- long ms = port->ms;
- HANDLE p = port->port;
-
- if (ms <= 0)
- ms = INFINITE;
-
- while (1) {
- OVERLAPPED *overlapped=NULL;
- ULONG_PTR key=0;
- DWORD bytes=0;
- int ok = GetQueuedCompletionStatus(p, &bytes, &key,
- &overlapped, ms);
- EnterCriticalSection(&port->lock);
- if (port->shutdown) {
- if (--port->n_live_threads == 0)
- ReleaseSemaphore(port->shutdownSemaphore, 1,
- NULL);
- LeaveCriticalSection(&port->lock);
- return;
- }
- LeaveCriticalSection(&port->lock);
-
- if (key != NOTIFICATION_KEY && overlapped)
- handle_entry(overlapped, key, bytes, ok);
- else if (!overlapped)
- break;
- }
- event_warnx("GetQueuedCompletionStatus exited with no event.");
- EnterCriticalSection(&port->lock);
- if (--port->n_live_threads == 0)
- ReleaseSemaphore(port->shutdownSemaphore, 1, NULL);
- LeaveCriticalSection(&port->lock);
-}
-
-int
-event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
- ev_uintptr_t key)
-{
- HANDLE h;
- h = CreateIoCompletionPort((HANDLE)fd, port->port, key, port->n_threads);
- if (!h)
- return -1;
- return 0;
-}
-
-static void *
-get_extension_function(SOCKET s, const GUID *which_fn)
-{
- void *ptr = NULL;
- DWORD bytes=0;
- WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
- (GUID*)which_fn, sizeof(*which_fn),
- &ptr, sizeof(ptr),
- &bytes, NULL, NULL);
-
- /* No need to detect errors here: if ptr is set, then we have a good
- function pointer. Otherwise, we should behave as if we had no
- function pointer.
- */
- return ptr;
-}
-
-/* Mingw doesn't have these in its mswsock.h. The values are copied from
- wine.h. Perhaps if we copy them exactly, the cargo will come again.
-*/
-#ifndef WSAID_ACCEPTEX
-#define WSAID_ACCEPTEX \
- {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
-#endif
-#ifndef WSAID_CONNECTEX
-#define WSAID_CONNECTEX \
- {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
-#endif
-#ifndef WSAID_GETACCEPTEXSOCKADDRS
-#define WSAID_GETACCEPTEXSOCKADDRS \
- {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
-#endif
-
-static int extension_fns_initialized = 0;
-
-static void
-init_extension_functions(struct win32_extension_fns *ext)
-{
- const GUID acceptex = WSAID_ACCEPTEX;
- const GUID connectex = WSAID_CONNECTEX;
- const GUID getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
- SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
- if (s == INVALID_SOCKET)
- return;
- ext->AcceptEx = get_extension_function(s, &acceptex);
- ext->ConnectEx = get_extension_function(s, &connectex);
- ext->GetAcceptExSockaddrs = get_extension_function(s,
- &getacceptexsockaddrs);
- closesocket(s);
-
- extension_fns_initialized = 1;
-}
-
-static struct win32_extension_fns the_extension_fns;
-
-const struct win32_extension_fns *
-event_get_win32_extension_fns_(void)
-{
- return &the_extension_fns;
-}
-
-#define N_CPUS_DEFAULT 2
-
-struct event_iocp_port *
-event_iocp_port_launch_(int n_cpus)
-{
- struct event_iocp_port *port;
- int i;
-
- if (!extension_fns_initialized)
- init_extension_functions(&the_extension_fns);
-
- if (!(port = mm_calloc(1, sizeof(struct event_iocp_port))))
- return NULL;
-
- if (n_cpus <= 0)
- n_cpus = N_CPUS_DEFAULT;
- port->n_threads = n_cpus * 2;
- port->threads = mm_calloc(port->n_threads, sizeof(HANDLE));
- if (!port->threads)
- goto err;
-
- port->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
- n_cpus);
- port->ms = -1;
- if (!port->port)
- goto err;
-
- port->shutdownSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
- if (!port->shutdownSemaphore)
- goto err;
-
- for (i=0; i<port->n_threads; ++i) {
- ev_uintptr_t th = _beginthread(loop, 0, port);
- if (th == (ev_uintptr_t)-1)
- goto err;
- port->threads[i] = (HANDLE)th;
- ++port->n_live_threads;
- }
-
- InitializeCriticalSectionAndSpinCount(&port->lock, 1000);
-
- return port;
-err:
- if (port->port)
- CloseHandle(port->port);
- if (port->threads)
- mm_free(port->threads);
- if (port->shutdownSemaphore)
- CloseHandle(port->shutdownSemaphore);
- mm_free(port);
- return NULL;
-}
-
-static void
-event_iocp_port_unlock_and_free_(struct event_iocp_port *port)
-{
- DeleteCriticalSection(&port->lock);
- CloseHandle(port->port);
- CloseHandle(port->shutdownSemaphore);
- mm_free(port->threads);
- mm_free(port);
-}
-
-static int
-event_iocp_notify_all(struct event_iocp_port *port)
-{
- int i, r, ok=1;
- for (i=0; i<port->n_threads; ++i) {
- r = PostQueuedCompletionStatus(port->port, 0, NOTIFICATION_KEY,
- NULL);
- if (!r)
- ok = 0;
- }
- return ok ? 0 : -1;
-}
-
-int
-event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec)
-{
- DWORD ms = INFINITE;
- int n;
-
- EnterCriticalSection(&port->lock);
- port->shutdown = 1;
- LeaveCriticalSection(&port->lock);
- event_iocp_notify_all(port);
-
- if (waitMsec >= 0)
- ms = waitMsec;
-
- WaitForSingleObject(port->shutdownSemaphore, ms);
- EnterCriticalSection(&port->lock);
- n = port->n_live_threads;
- LeaveCriticalSection(&port->lock);
- if (n == 0) {
- event_iocp_port_unlock_and_free_(port);
- return 0;
- } else {
- return -1;
- }
-}
-
-int
-event_iocp_activate_overlapped_(
- struct event_iocp_port *port, struct event_overlapped *o,
- ev_uintptr_t key, ev_uint32_t n)
-{
- BOOL r;
-
- r = PostQueuedCompletionStatus(port->port, n, key, &o->overlapped);
- return (r==0) ? -1 : 0;
-}
-
-struct event_iocp_port *
-event_base_get_iocp_(struct event_base *base)
-{
-#ifdef _WIN32
- return base->iocp;
-#else
- return NULL;
-#endif
-}
diff --git a/libs/libevent/src/event_tagging.c b/libs/libevent/src/event_tagging.c
deleted file mode 100644
index 6459dfa72e..0000000000
--- a/libs/libevent/src/event_tagging.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Copyright (c) 2003-2009 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef EVENT__HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef EVENT__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
-#endif
-
-#ifdef EVENT__HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#include <sys/queue.h>
-#ifdef EVENT__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 EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <limits.h>
-
-#include "event2/event.h"
-#include "event2/tag.h"
-#include "event2/buffer.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "util-internal.h"
-
-/*
- Here's our wire format:
-
- Stream = TaggedData*
-
- TaggedData = Tag Length Data
- where the integer value of 'Length' is the length of 'data'.
-
- Tag = HByte* LByte
- where HByte is a byte with the high bit set, and LByte is a byte
- with the high bit clear. The integer value of the tag is taken
- by concatenating the lower 7 bits from all the tags. So for example,
- the tag 0x66 is encoded as [66], whereas the tag 0x166 is encoded as
- [82 66]
-
- Length = Integer
-
- Integer = NNibbles Nibble* Padding?
- where NNibbles is a 4-bit value encoding the number of nibbles-1,
- and each Nibble is 4 bits worth of encoded integer, in big-endian
- order. If the total encoded integer size is an odd number of nibbles,
- a final padding nibble with value 0 is appended.
-*/
-
-int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
-int evtag_decode_int64(ev_uint64_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);
-
-void
-evtag_init(void)
-{
-}
-
-/*
- * We encode integers 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 number a 32-bit unsigned integer to encode
- * @param data a pointer to where the data should be written. Must
- * have at least 5 bytes free.
- * @return the number of bytes written into data.
- */
-
-#define ENCODE_INT_INTERNAL(data, number) do { \
- int off = 1, nibbles = 0; \
- \
- memset(data, 0, sizeof(number)+1); \
- while (number) { \
- if (off & 0x1) \
- data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f); \
- else \
- data[off/2] = (data[off/2] & 0x0f) | \
- ((number & 0x0f) << 4); \
- number >>= 4; \
- off++; \
- } \
- \
- if (off > 2) \
- nibbles = off - 2; \
- \
- /* Off - 1 is the number of encoded nibbles */ \
- data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4); \
- \
- return ((off + 1) / 2); \
-} while (0)
-
-static inline int
-encode_int_internal(ev_uint8_t *data, ev_uint32_t number)
-{
- ENCODE_INT_INTERNAL(data, number);
-}
-
-static inline int
-encode_int64_internal(ev_uint8_t *data, ev_uint64_t number)
-{
- ENCODE_INT_INTERNAL(data, number);
-}
-
-void
-evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number)
-{
- ev_uint8_t data[5];
- int len = encode_int_internal(data, number);
- evbuffer_add(evbuf, data, len);
-}
-
-void
-evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number)
-{
- ev_uint8_t data[9];
- int len = encode_int64_internal(data, number);
- evbuffer_add(evbuf, data, len);
-}
-
-/*
- * 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;
- size_t len = evbuffer_get_length(evbuf);
- ev_uint8_t *data;
- size_t count = 0;
- int shift = 0, done = 0;
-
- /*
- * the encoding of a number is at most one byte more than its
- * storage size. however, it may also be much smaller.
- */
- data = evbuffer_pullup(
- evbuf, len < sizeof(number) + 1 ? len : sizeof(number) + 1);
- if (!data)
- return (-1);
-
- while (count++ < len) {
- ev_uint8_t lower = *data++;
- if (shift >= 28) {
- /* Make sure it fits into 32 bits */
- if (shift > 28)
- return (-1);
- if ((lower & 0x7f) > 15)
- return (-1);
- }
- number |= (lower & (unsigned)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_MAX ? INT_MAX : (int)(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);
- evtag_encode_int(evbuf, len);
- evbuffer_add(evbuf, (void *)data, len);
-}
-
-void
-evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
- struct evbuffer *data)
-{
- evtag_encode_tag(evbuf, tag);
- /* XXX support more than UINT32_MAX data */
- evtag_encode_int(evbuf, (ev_uint32_t)evbuffer_get_length(data));
- evbuffer_add_buffer(evbuf, data);
-}
-
-/* Marshaling for integers */
-void
-evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
-{
- ev_uint8_t data[5];
- int len = encode_int_internal(data, integer);
-
- evtag_encode_tag(evbuf, tag);
- evtag_encode_int(evbuf, len);
- evbuffer_add(evbuf, data, len);
-}
-
-void
-evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag,
- ev_uint64_t integer)
-{
- ev_uint8_t data[9];
- int len = encode_int64_internal(data, integer);
-
- evtag_encode_tag(evbuf, tag);
- evtag_encode_int(evbuf, len);
- evbuffer_add(evbuf, data, len);
-}
-
-void
-evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
-{
- /* TODO support strings longer than UINT32_MAX ? */
- evtag_marshal(buf, tag, string, (ev_uint32_t)strlen(string));
-}
-
-void
-evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
-{
- ev_uint8_t data[10];
- int len = encode_int_internal(data, tv->tv_sec);
- len += encode_int_internal(data + len, tv->tv_usec);
- evtag_marshal(evbuf, tag, data, len);
-}
-
-#define DECODE_INT_INTERNAL(number, maxnibbles, pnumber, evbuf, offset) \
-do { \
- ev_uint8_t *data; \
- ev_ssize_t len = evbuffer_get_length(evbuf) - offset; \
- int nibbles = 0; \
- \
- if (len <= 0) \
- return (-1); \
- \
- /* XXX(niels): faster? */ \
- data = evbuffer_pullup(evbuf, offset + 1) + offset; \
- if (!data) \
- return (-1); \
- \
- nibbles = ((data[0] & 0xf0) >> 4) + 1; \
- if (nibbles > maxnibbles || (nibbles >> 1) + 1 > len) \
- return (-1); \
- len = (nibbles >> 1) + 1; \
- \
- data = evbuffer_pullup(evbuf, offset + len) + offset; \
- if (!data) \
- return (-1); \
- \
- while (nibbles > 0) { \
- number <<= 4; \
- if (nibbles & 0x1) \
- number |= data[nibbles >> 1] & 0x0f; \
- else \
- number |= (data[nibbles >> 1] & 0xf0) >> 4; \
- nibbles--; \
- } \
- \
- *pnumber = number; \
- \
- return (int)(len); \
-} while (0)
-
-/* Internal: decode an integer from an evbuffer, without draining it.
- * Only integers up to 32-bits are supported.
- *
- * @param evbuf the buffer to read from
- * @param offset an index into the buffer at which we should start reading.
- * @param pnumber a pointer to receive the integer.
- * @return The length of the number as encoded, or -1 on error.
- */
-
-static int
-decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int offset)
-{
- ev_uint32_t number = 0;
- DECODE_INT_INTERNAL(number, 8, pnumber, evbuf, offset);
-}
-
-static int
-decode_int64_internal(ev_uint64_t *pnumber, struct evbuffer *evbuf, int offset)
-{
- ev_uint64_t number = 0;
- DECODE_INT_INTERNAL(number, 16, pnumber, evbuf, offset);
-}
-
-int
-evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
-{
- int res = decode_int_internal(pnumber, evbuf, 0);
- if (res != -1)
- evbuffer_drain(evbuf, res);
-
- return (res == -1 ? -1 : 0);
-}
-
-int
-evtag_decode_int64(ev_uint64_t *pnumber, struct evbuffer *evbuf)
-{
- int res = decode_int64_internal(pnumber, evbuf, 0);
- if (res != -1)
- evbuffer_drain(evbuf, res);
-
- return (res == -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)
-{
- int res, len;
-
- len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
- if (len == -1)
- return (-1);
-
- res = decode_int_internal(plength, evbuf, len);
- if (res == -1)
- return (-1);
-
- *plength += res + len;
-
- return (0);
-}
-
-int
-evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
-{
- int res, len;
-
- len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
- if (len == -1)
- return (-1);
-
- res = decode_int_internal(plength, evbuf, len);
- if (res == -1)
- return (-1);
-
- return (0);
-}
-
-/* just unmarshals the header and returns the length of the remaining data */
-
-int
-evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag)
-{
- ev_uint32_t len;
-
- if (decode_tag_internal(ptag, evbuf, 1 /* dodrain */) == -1)
- return (-1);
- if (evtag_decode_int(&len, evbuf) == -1)
- return (-1);
-
- if (evbuffer_get_length(evbuf) < len)
- return (-1);
-
- return (len);
-}
-
-int
-evtag_consume(struct evbuffer *evbuf)
-{
- int len;
- if ((len = evtag_unmarshal_header(evbuf, NULL)) == -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)
-{
- int len;
-
- if ((len = evtag_unmarshal_header(src, ptag)) == -1)
- return (-1);
-
- if (evbuffer_add(dst, evbuffer_pullup(src, len), 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;
- int result;
-
- if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
- return (-1);
- if (need_tag != tag)
- return (-1);
- if (evtag_decode_int(&len, evbuf) == -1)
- return (-1);
-
- if (evbuffer_get_length(evbuf) < len)
- return (-1);
-
- result = decode_int_internal(pinteger, evbuf, 0);
- evbuffer_drain(evbuf, len);
- if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/
- return (-1);
- else
- return result;
-}
-
-int
-evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag,
- ev_uint64_t *pinteger)
-{
- ev_uint32_t tag;
- ev_uint32_t len;
- int result;
-
- if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
- return (-1);
- if (need_tag != tag)
- return (-1);
- if (evtag_decode_int(&len, evbuf) == -1)
- return (-1);
-
- if (evbuffer_get_length(evbuf) < len)
- return (-1);
-
- result = decode_int64_internal(pinteger, evbuf, 0);
- evbuffer_drain(evbuf, len);
- if (result < 0 || (size_t)result > len) /* XXX Should this be != rather than > ?*/
- return (-1);
- else
- return result;
-}
-
-/* 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;
- int tag_len;
-
- /* Now unmarshal a tag and check that it matches the tag we want */
- if ((tag_len = evtag_unmarshal_header(src, &tag)) < 0 ||
- tag != need_tag)
- return (-1);
-
- if ((size_t)tag_len != len)
- return (-1);
-
- evbuffer_remove(src, data, len);
- return (0);
-}
-
-int
-evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
- char **pstring)
-{
- ev_uint32_t tag;
- int tag_len;
-
- if ((tag_len = evtag_unmarshal_header(evbuf, &tag)) == -1 ||
- tag != need_tag)
- return (-1);
-
- *pstring = mm_malloc(tag_len + 1);
- if (*pstring == NULL) {
- event_warn("%s: malloc", __func__);
- return -1;
- }
- evbuffer_remove(evbuf, *pstring, tag_len);
- (*pstring)[tag_len] = '\0';
-
- 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;
- int len, offset, offset2;
- int result = -1;
-
- if ((len = evtag_unmarshal_header(evbuf, &tag)) == -1)
- return (-1);
- if (tag != need_tag)
- goto done;
- if ((offset = decode_int_internal(&integer, evbuf, 0)) == -1)
- goto done;
- ptv->tv_sec = integer;
- if ((offset2 = decode_int_internal(&integer, evbuf, offset)) == -1)
- goto done;
- ptv->tv_usec = integer;
- if (offset + offset2 > len) /* XXX Should this be != instead of > ? */
- goto done;
-
- result = 0;
- done:
- evbuffer_drain(evbuf, len);
- return result;
-}
diff --git a/libs/libevent/src/evmap-internal.h b/libs/libevent/src/evmap-internal.h
deleted file mode 100644
index dfc81d5087..0000000000
--- a/libs/libevent/src/evmap-internal.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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 EVMAP_INTERNAL_H_INCLUDED_
-#define EVMAP_INTERNAL_H_INCLUDED_
-
-/** @file evmap-internal.h
- *
- * An event_map is a utility structure to map each fd or signal to zero or
- * more events. Functions to manipulate event_maps should only be used from
- * inside libevent. They generally need to hold the lock on the corresponding
- * event_base.
- **/
-
-struct event_base;
-struct event;
-
-/** Initialize an event_map for use.
- */
-void evmap_io_initmap_(struct event_io_map* ctx);
-void evmap_signal_initmap_(struct event_signal_map* ctx);
-
-/** Remove all entries from an event_map.
-
- @param ctx the map to clear.
- */
-void evmap_io_clear_(struct event_io_map* ctx);
-void evmap_signal_clear_(struct event_signal_map* ctx);
-
-/** Add an IO event (some combination of EV_READ or EV_WRITE) to an
- event_base's list of events on a given file descriptor, and tell the
- underlying eventops about the fd if its state has changed.
-
- Requires that ev is not already added.
-
- @param base the event_base to operate on.
- @param fd the file descriptor corresponding to ev.
- @param ev the event to add.
-*/
-int evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev);
-/** Remove an IO event (some combination of EV_READ or EV_WRITE) to an
- event_base's list of events on a given file descriptor, and tell the
- underlying eventops about the fd if its state has changed.
-
- @param base the event_base to operate on.
- @param fd the file descriptor corresponding to ev.
- @param ev the event to remove.
- */
-int evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev);
-/** Active the set of events waiting on an event_base for a given fd.
-
- @param base the event_base to operate on.
- @param fd the file descriptor that has become active.
- @param events a bitmask of EV_READ|EV_WRITE|EV_ET.
-*/
-void evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events);
-
-
-/* These functions behave in the same way as evmap_io_*, except they work on
- * signals rather than fds. signals use a linear map everywhere; fds use
- * either a linear map or a hashtable. */
-int evmap_signal_add_(struct event_base *base, int signum, struct event *ev);
-int evmap_signal_del_(struct event_base *base, int signum, struct event *ev);
-void evmap_signal_active_(struct event_base *base, evutil_socket_t signum, int ncalls);
-
-/* Return the fdinfo object associated with a given fd. If the fd has no
- * events associated with it, the result may be NULL.
- */
-void *evmap_io_get_fdinfo_(struct event_io_map *ctx, evutil_socket_t fd);
-
-/* Helper for event_reinit(): Tell the backend to re-add every fd and signal
- * for which we have a pending event.
- */
-int evmap_reinit_(struct event_base *base);
-
-/* Helper for event_base_free(): Call event_del() on every pending fd and
- * signal event.
- */
-void evmap_delete_all_(struct event_base *base);
-
-/* Helper for event_base_assert_ok_(): Check referential integrity of the
- * evmaps.
- */
-void evmap_check_integrity_(struct event_base *base);
-
-/* Helper: Call fn on every fd or signal event, passing as its arguments the
- * provided event_base, the event, and arg. If fn returns 0, process the next
- * event. If it returns any other value, return that value and process no
- * more events.
- */
-int evmap_foreach_event_(struct event_base *base,
- event_base_foreach_event_cb fn,
- void *arg);
-
-#endif /* EVMAP_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/evmap.c b/libs/libevent/src/evmap.c
deleted file mode 100644
index 3f76dd0ae1..0000000000
--- a/libs/libevent/src/evmap.c
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#endif
-#include <sys/types.h>
-#if !defined(_WIN32) && defined(EVENT__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 <time.h>
-
-#include "event-internal.h"
-#include "evmap-internal.h"
-#include "mm-internal.h"
-#include "changelist-internal.h"
-
-/** An entry for an evmap_io list: notes all the events that want to read or
- write on a given fd, and the number of each.
- */
-struct evmap_io {
- struct event_dlist events;
- ev_uint16_t nread;
- ev_uint16_t nwrite;
- ev_uint16_t nclose;
-};
-
-/* An entry for an evmap_signal list: notes all the events that want to know
- when a signal triggers. */
-struct evmap_signal {
- struct event_dlist events;
-};
-
-/* On some platforms, fds start at 0 and increment by 1 as they are
- allocated, and old numbers get used. For these platforms, we
- implement io maps just like signal maps: as an array of pointers to
- struct evmap_io. But on other platforms (windows), sockets are not
- 0-indexed, not necessarily consecutive, and not necessarily reused.
- There, we use a hashtable to implement evmap_io.
-*/
-#ifdef EVMAP_USE_HT
-struct event_map_entry {
- HT_ENTRY(event_map_entry) map_node;
- evutil_socket_t fd;
- union { /* This is a union in case we need to make more things that can
- be in the hashtable. */
- struct evmap_io evmap_io;
- } ent;
-};
-
-/* Helper used by the event_io_map hashtable code; tries to return a good hash
- * of the fd in e->fd. */
-static inline unsigned
-hashsocket(struct event_map_entry *e)
-{
- /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
- * matter. Our hashtable implementation really likes low-order bits,
- * though, so let's do the rotate-and-add trick. */
- unsigned h = (unsigned) e->fd;
- h += (h >> 2) | (h << 30);
- return h;
-}
-
-/* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
- * have the same e->fd. */
-static inline int
-eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
-{
- return e1->fd == e2->fd;
-}
-
-HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
-HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
- 0.5, mm_malloc, mm_realloc, mm_free)
-
-#define GET_IO_SLOT(x, map, slot, type) \
- do { \
- struct event_map_entry key_, *ent_; \
- key_.fd = slot; \
- ent_ = HT_FIND(event_io_map, map, &key_); \
- (x) = ent_ ? &ent_->ent.type : NULL; \
- } while (0);
-
-#define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
- do { \
- struct event_map_entry key_, *ent_; \
- key_.fd = slot; \
- HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
- event_map_entry, &key_, ptr, \
- { \
- ent_ = *ptr; \
- }, \
- { \
- ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
- if (EVUTIL_UNLIKELY(ent_ == NULL)) \
- return (-1); \
- ent_->fd = slot; \
- (ctor)(&ent_->ent.type); \
- HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
- }); \
- (x) = &ent_->ent.type; \
- } while (0)
-
-void evmap_io_initmap_(struct event_io_map *ctx)
-{
- HT_INIT(event_io_map, ctx);
-}
-
-void evmap_io_clear_(struct event_io_map *ctx)
-{
- struct event_map_entry **ent, **next, *this;
- for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
- this = *ent;
- next = HT_NEXT_RMV(event_io_map, ctx, ent);
- mm_free(this);
- }
- HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
-}
-#endif
-
-/* Set the variable 'x' to the field in event_map 'map' with fields of type
- 'struct type *' corresponding to the fd or signal 'slot'. Set 'x' to NULL
- if there are no entries for 'slot'. Does no bounds-checking. */
-#define GET_SIGNAL_SLOT(x, map, slot, type) \
- (x) = (struct type *)((map)->entries[slot])
-/* As GET_SLOT, but construct the entry for 'slot' if it is not present,
- by allocating enough memory for a 'struct type', and initializing the new
- value by calling the function 'ctor' on it. Makes the function
- return -1 on allocation failure.
- */
-#define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
- do { \
- if ((map)->entries[slot] == NULL) { \
- (map)->entries[slot] = \
- mm_calloc(1,sizeof(struct type)+fdinfo_len); \
- if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
- return (-1); \
- (ctor)((struct type *)(map)->entries[slot]); \
- } \
- (x) = (struct type *)((map)->entries[slot]); \
- } while (0)
-
-/* If we aren't using hashtables, then define the IO_SLOT macros and functions
- as thin aliases over the SIGNAL_SLOT versions. */
-#ifndef EVMAP_USE_HT
-#define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
-#define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \
- GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
-#define FDINFO_OFFSET sizeof(struct evmap_io)
-void
-evmap_io_initmap_(struct event_io_map* ctx)
-{
- evmap_signal_initmap_(ctx);
-}
-void
-evmap_io_clear_(struct event_io_map* ctx)
-{
- evmap_signal_clear_(ctx);
-}
-#endif
-
-
-/** Expand 'map' with new entries of width 'msize' until it is big enough
- to store a value in 'slot'.
- */
-static int
-evmap_make_space(struct event_signal_map *map, int slot, int msize)
-{
- if (map->nentries <= slot) {
- int nentries = map->nentries ? map->nentries : 32;
- void **tmp;
-
- while (nentries <= slot)
- nentries <<= 1;
-
- tmp = (void **)mm_realloc(map->entries, nentries * msize);
- if (tmp == NULL)
- return (-1);
-
- memset(&tmp[map->nentries], 0,
- (nentries - map->nentries) * msize);
-
- map->nentries = nentries;
- map->entries = tmp;
- }
-
- return (0);
-}
-
-void
-evmap_signal_initmap_(struct event_signal_map *ctx)
-{
- ctx->nentries = 0;
- ctx->entries = NULL;
-}
-
-void
-evmap_signal_clear_(struct event_signal_map *ctx)
-{
- if (ctx->entries != NULL) {
- int i;
- for (i = 0; i < ctx->nentries; ++i) {
- if (ctx->entries[i] != NULL)
- mm_free(ctx->entries[i]);
- }
- mm_free(ctx->entries);
- ctx->entries = NULL;
- }
- ctx->nentries = 0;
-}
-
-
-/* code specific to file descriptors */
-
-/** Constructor for struct evmap_io */
-static void
-evmap_io_init(struct evmap_io *entry)
-{
- LIST_INIT(&entry->events);
- entry->nread = 0;
- entry->nwrite = 0;
- entry->nclose = 0;
-}
-
-
-/* return -1 on error, 0 on success if nothing changed in the event backend,
- * and 1 on success if something did. */
-int
-evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
-{
- const struct eventop *evsel = base->evsel;
- struct event_io_map *io = &base->io;
- struct evmap_io *ctx = NULL;
- int nread, nwrite, nclose, retval = 0;
- short res = 0, old = 0;
- struct event *old_ev;
-
- EVUTIL_ASSERT(fd == ev->ev_fd);
-
- if (fd < 0)
- return 0;
-
-#ifndef EVMAP_USE_HT
- if (fd >= io->nentries) {
- if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
- return (-1);
- }
-#endif
- GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
- evsel->fdinfo_len);
-
- nread = ctx->nread;
- nwrite = ctx->nwrite;
- nclose = ctx->nclose;
-
- if (nread)
- old |= EV_READ;
- if (nwrite)
- old |= EV_WRITE;
- if (nclose)
- old |= EV_CLOSED;
-
- if (ev->ev_events & EV_READ) {
- if (++nread == 1)
- res |= EV_READ;
- }
- if (ev->ev_events & EV_WRITE) {
- if (++nwrite == 1)
- res |= EV_WRITE;
- }
- if (ev->ev_events & EV_CLOSED) {
- if (++nclose == 1)
- res |= EV_CLOSED;
- }
- if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
- event_warnx("Too many events reading or writing on fd %d",
- (int)fd);
- return -1;
- }
- if (EVENT_DEBUG_MODE_IS_ON() &&
- (old_ev = LIST_FIRST(&ctx->events)) &&
- (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
- event_warnx("Tried to mix edge-triggered and non-edge-triggered"
- " events on fd %d", (int)fd);
- return -1;
- }
-
- if (res) {
- void *extra = ((char*)ctx) + sizeof(struct evmap_io);
- /* XXX(niels): we cannot mix edge-triggered and
- * level-triggered, we should probably assert on
- * this. */
- if (evsel->add(base, ev->ev_fd,
- old, (ev->ev_events & EV_ET) | res, extra) == -1)
- return (-1);
- retval = 1;
- }
-
- ctx->nread = (ev_uint16_t) nread;
- ctx->nwrite = (ev_uint16_t) nwrite;
- ctx->nclose = (ev_uint16_t) nclose;
- LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
-
- return (retval);
-}
-
-/* return -1 on error, 0 on success if nothing changed in the event backend,
- * and 1 on success if something did. */
-int
-evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
-{
- const struct eventop *evsel = base->evsel;
- struct event_io_map *io = &base->io;
- struct evmap_io *ctx;
- int nread, nwrite, nclose, retval = 0;
- short res = 0, old = 0;
-
- if (fd < 0)
- return 0;
-
- EVUTIL_ASSERT(fd == ev->ev_fd);
-
-#ifndef EVMAP_USE_HT
- if (fd >= io->nentries)
- return (-1);
-#endif
-
- GET_IO_SLOT(ctx, io, fd, evmap_io);
-
- nread = ctx->nread;
- nwrite = ctx->nwrite;
- nclose = ctx->nclose;
-
- if (nread)
- old |= EV_READ;
- if (nwrite)
- old |= EV_WRITE;
- if (nclose)
- old |= EV_CLOSED;
-
- if (ev->ev_events & EV_READ) {
- if (--nread == 0)
- res |= EV_READ;
- EVUTIL_ASSERT(nread >= 0);
- }
- if (ev->ev_events & EV_WRITE) {
- if (--nwrite == 0)
- res |= EV_WRITE;
- EVUTIL_ASSERT(nwrite >= 0);
- }
- if (ev->ev_events & EV_CLOSED) {
- if (--nclose == 0)
- res |= EV_CLOSED;
- EVUTIL_ASSERT(nclose >= 0);
- }
-
- if (res) {
- void *extra = ((char*)ctx) + sizeof(struct evmap_io);
- if (evsel->del(base, ev->ev_fd, old, res, extra) == -1) {
- retval = -1;
- } else {
- retval = 1;
- }
- }
-
- ctx->nread = nread;
- ctx->nwrite = nwrite;
- ctx->nclose = nclose;
- LIST_REMOVE(ev, ev_io_next);
-
- return (retval);
-}
-
-void
-evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
-{
- struct event_io_map *io = &base->io;
- struct evmap_io *ctx;
- struct event *ev;
-
-#ifndef EVMAP_USE_HT
- if (fd < 0 || fd >= io->nentries)
- return;
-#endif
- GET_IO_SLOT(ctx, io, fd, evmap_io);
-
- if (NULL == ctx)
- return;
- LIST_FOREACH(ev, &ctx->events, ev_io_next) {
- if (ev->ev_events & events)
- event_active_nolock_(ev, ev->ev_events & events, 1);
- }
-}
-
-/* code specific to signals */
-
-static void
-evmap_signal_init(struct evmap_signal *entry)
-{
- LIST_INIT(&entry->events);
-}
-
-
-int
-evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
-{
- const struct eventop *evsel = base->evsigsel;
- struct event_signal_map *map = &base->sigmap;
- struct evmap_signal *ctx = NULL;
-
- if (sig >= map->nentries) {
- if (evmap_make_space(
- map, sig, sizeof(struct evmap_signal *)) == -1)
- return (-1);
- }
- GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
- base->evsigsel->fdinfo_len);
-
- if (LIST_EMPTY(&ctx->events)) {
- if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
- == -1)
- return (-1);
- }
-
- LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
-
- return (1);
-}
-
-int
-evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
-{
- const struct eventop *evsel = base->evsigsel;
- struct event_signal_map *map = &base->sigmap;
- struct evmap_signal *ctx;
-
- if (sig >= map->nentries)
- return (-1);
-
- GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
-
- LIST_REMOVE(ev, ev_signal_next);
-
- if (LIST_FIRST(&ctx->events) == NULL) {
- if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
- return (-1);
- }
-
- return (1);
-}
-
-void
-evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
-{
- struct event_signal_map *map = &base->sigmap;
- struct evmap_signal *ctx;
- struct event *ev;
-
- if (sig < 0 || sig >= map->nentries)
- return;
- GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
-
- if (!ctx)
- return;
- LIST_FOREACH(ev, &ctx->events, ev_signal_next)
- event_active_nolock_(ev, EV_SIGNAL, ncalls);
-}
-
-void *
-evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
-{
- struct evmap_io *ctx;
- GET_IO_SLOT(ctx, map, fd, evmap_io);
- if (ctx)
- return ((char*)ctx) + sizeof(struct evmap_io);
- else
- return NULL;
-}
-
-/* Callback type for evmap_io_foreach_fd */
-typedef int (*evmap_io_foreach_fd_cb)(
- struct event_base *, evutil_socket_t, struct evmap_io *, void *);
-
-/* Multipurpose helper function: Iterate over every file descriptor event_base
- * for which we could have EV_READ or EV_WRITE events. For each such fd, call
- * fn(base, signum, evmap_io, arg), where fn is the user-provided
- * function, base is the event_base, signum is the signal number, evmap_io
- * is an evmap_io structure containing a list of events pending on the
- * file descriptor, and arg is the user-supplied argument.
- *
- * If fn returns 0, continue on to the next signal. Otherwise, return the same
- * value that fn returned.
- *
- * Note that there is no guarantee that the file descriptors will be processed
- * in any particular order.
- */
-static int
-evmap_io_foreach_fd(struct event_base *base,
- evmap_io_foreach_fd_cb fn,
- void *arg)
-{
- evutil_socket_t fd;
- struct event_io_map *iomap = &base->io;
- int r = 0;
-#ifdef EVMAP_USE_HT
- struct event_map_entry **mapent;
- HT_FOREACH(mapent, event_io_map, iomap) {
- struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
- fd = (*mapent)->fd;
-#else
- for (fd = 0; fd < iomap->nentries; ++fd) {
- struct evmap_io *ctx = iomap->entries[fd];
- if (!ctx)
- continue;
-#endif
- if ((r = fn(base, fd, ctx, arg)))
- break;
- }
- return r;
-}
-
-/* Callback type for evmap_signal_foreach_signal */
-typedef int (*evmap_signal_foreach_signal_cb)(
- struct event_base *, int, struct evmap_signal *, void *);
-
-/* Multipurpose helper function: Iterate over every signal number in the
- * event_base for which we could have signal events. For each such signal,
- * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
- * function, base is the event_base, signum is the signal number, evmap_signal
- * is an evmap_signal structure containing a list of events pending on the
- * signal, and arg is the user-supplied argument.
- *
- * If fn returns 0, continue on to the next signal. Otherwise, return the same
- * value that fn returned.
- */
-static int
-evmap_signal_foreach_signal(struct event_base *base,
- evmap_signal_foreach_signal_cb fn,
- void *arg)
-{
- struct event_signal_map *sigmap = &base->sigmap;
- int r = 0;
- int signum;
-
- for (signum = 0; signum < sigmap->nentries; ++signum) {
- struct evmap_signal *ctx = sigmap->entries[signum];
- if (!ctx)
- continue;
- if ((r = fn(base, signum, ctx, arg)))
- break;
- }
- return r;
-}
-
-/* Helper for evmap_reinit_: tell the backend to add every fd for which we have
- * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
- * EV_ET. */
-static int
-evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
- struct evmap_io *ctx, void *arg)
-{
- const struct eventop *evsel = base->evsel;
- void *extra;
- int *result = arg;
- short events = 0;
- struct event *ev;
- EVUTIL_ASSERT(ctx);
-
- extra = ((char*)ctx) + sizeof(struct evmap_io);
- if (ctx->nread)
- events |= EV_READ;
- if (ctx->nwrite)
- events |= EV_WRITE;
- if (ctx->nclose)
- events |= EV_CLOSED;
- if (evsel->fdinfo_len)
- memset(extra, 0, evsel->fdinfo_len);
- if (events &&
- (ev = LIST_FIRST(&ctx->events)) &&
- (ev->ev_events & EV_ET))
- events |= EV_ET;
- if (evsel->add(base, fd, 0, events, extra) == -1)
- *result = -1;
-
- return 0;
-}
-
-/* Helper for evmap_reinit_: tell the backend to add every signal for which we
- * have pending events. */
-static int
-evmap_signal_reinit_iter_fn(struct event_base *base,
- int signum, struct evmap_signal *ctx, void *arg)
-{
- const struct eventop *evsel = base->evsigsel;
- int *result = arg;
-
- if (!LIST_EMPTY(&ctx->events)) {
- if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
- *result = -1;
- }
- return 0;
-}
-
-int
-evmap_reinit_(struct event_base *base)
-{
- int result = 0;
-
- evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
- if (result < 0)
- return -1;
- evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
- if (result < 0)
- return -1;
- return 0;
-}
-
-/* Helper for evmap_delete_all_: delete every event in an event_dlist. */
-static int
-delete_all_in_dlist(struct event_dlist *dlist)
-{
- struct event *ev;
- while ((ev = LIST_FIRST(dlist)))
- event_del(ev);
- return 0;
-}
-
-/* Helper for evmap_delete_all_: delete every event pending on an fd. */
-static int
-evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
- struct evmap_io *io_info, void *arg)
-{
- return delete_all_in_dlist(&io_info->events);
-}
-
-/* Helper for evmap_delete_all_: delete every event pending on a signal. */
-static int
-evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
- struct evmap_signal *sig_info, void *arg)
-{
- return delete_all_in_dlist(&sig_info->events);
-}
-
-void
-evmap_delete_all_(struct event_base *base)
-{
- evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
- evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
-}
-
-/** Per-fd structure for use with changelists. It keeps track, for each fd or
- * signal using the changelist, of where its entry in the changelist is.
- */
-struct event_changelist_fdinfo {
- int idxplus1; /* this is the index +1, so that memset(0) will make it
- * a no-such-element */
-};
-
-void
-event_changelist_init_(struct event_changelist *changelist)
-{
- changelist->changes = NULL;
- changelist->changes_size = 0;
- changelist->n_changes = 0;
-}
-
-/** Helper: return the changelist_fdinfo corresponding to a given change. */
-static inline struct event_changelist_fdinfo *
-event_change_get_fdinfo(struct event_base *base,
- const struct event_change *change)
-{
- char *ptr;
- if (change->read_change & EV_CHANGE_SIGNAL) {
- struct evmap_signal *ctx;
- GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
- ptr = ((char*)ctx) + sizeof(struct evmap_signal);
- } else {
- struct evmap_io *ctx;
- GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
- ptr = ((char*)ctx) + sizeof(struct evmap_io);
- }
- return (void*)ptr;
-}
-
-/** Callback helper for event_changelist_assert_ok */
-static int
-event_changelist_assert_ok_foreach_iter_fn(
- struct event_base *base,
- evutil_socket_t fd, struct evmap_io *io, void *arg)
-{
- struct event_changelist *changelist = &base->changelist;
- struct event_changelist_fdinfo *f;
- f = (void*)
- ( ((char*)io) + sizeof(struct evmap_io) );
- if (f->idxplus1) {
- struct event_change *c = &changelist->changes[f->idxplus1 - 1];
- EVUTIL_ASSERT(c->fd == fd);
- }
- return 0;
-}
-
-/** Make sure that the changelist is consistent with the evmap structures. */
-static void
-event_changelist_assert_ok(struct event_base *base)
-{
- int i;
- struct event_changelist *changelist = &base->changelist;
-
- EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
- for (i = 0; i < changelist->n_changes; ++i) {
- struct event_change *c = &changelist->changes[i];
- struct event_changelist_fdinfo *f;
- EVUTIL_ASSERT(c->fd >= 0);
- f = event_change_get_fdinfo(base, c);
- EVUTIL_ASSERT(f);
- EVUTIL_ASSERT(f->idxplus1 == i + 1);
- }
-
- evmap_io_foreach_fd(base,
- event_changelist_assert_ok_foreach_iter_fn,
- NULL);
-}
-
-#ifdef DEBUG_CHANGELIST
-#define event_changelist_check(base) event_changelist_assert_ok((base))
-#else
-#define event_changelist_check(base) ((void)0)
-#endif
-
-void
-event_changelist_remove_all_(struct event_changelist *changelist,
- struct event_base *base)
-{
- int i;
-
- event_changelist_check(base);
-
- for (i = 0; i < changelist->n_changes; ++i) {
- struct event_change *ch = &changelist->changes[i];
- struct event_changelist_fdinfo *fdinfo =
- event_change_get_fdinfo(base, ch);
- EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
- fdinfo->idxplus1 = 0;
- }
-
- changelist->n_changes = 0;
-
- event_changelist_check(base);
-}
-
-void
-event_changelist_freemem_(struct event_changelist *changelist)
-{
- if (changelist->changes)
- mm_free(changelist->changes);
- event_changelist_init_(changelist); /* zero it all out. */
-}
-
-/** Increase the size of 'changelist' to hold more changes. */
-static int
-event_changelist_grow(struct event_changelist *changelist)
-{
- int new_size;
- struct event_change *new_changes;
- if (changelist->changes_size < 64)
- new_size = 64;
- else
- new_size = changelist->changes_size * 2;
-
- new_changes = mm_realloc(changelist->changes,
- new_size * sizeof(struct event_change));
-
- if (EVUTIL_UNLIKELY(new_changes == NULL))
- return (-1);
-
- changelist->changes = new_changes;
- changelist->changes_size = new_size;
-
- return (0);
-}
-
-/** Return a pointer to the changelist entry for the file descriptor or signal
- * 'fd', whose fdinfo is 'fdinfo'. If none exists, construct it, setting its
- * old_events field to old_events.
- */
-static struct event_change *
-event_changelist_get_or_construct(struct event_changelist *changelist,
- evutil_socket_t fd,
- short old_events,
- struct event_changelist_fdinfo *fdinfo)
-{
- struct event_change *change;
-
- if (fdinfo->idxplus1 == 0) {
- int idx;
- EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
-
- if (changelist->n_changes == changelist->changes_size) {
- if (event_changelist_grow(changelist) < 0)
- return NULL;
- }
-
- idx = changelist->n_changes++;
- change = &changelist->changes[idx];
- fdinfo->idxplus1 = idx + 1;
-
- memset(change, 0, sizeof(struct event_change));
- change->fd = fd;
- change->old_events = old_events;
- } else {
- change = &changelist->changes[fdinfo->idxplus1 - 1];
- EVUTIL_ASSERT(change->fd == fd);
- }
- return change;
-}
-
-int
-event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
- void *p)
-{
- struct event_changelist *changelist = &base->changelist;
- struct event_changelist_fdinfo *fdinfo = p;
- struct event_change *change;
-
- event_changelist_check(base);
-
- change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
- if (!change)
- return -1;
-
- /* An add replaces any previous delete, but doesn't result in a no-op,
- * since the delete might fail (because the fd had been closed since
- * the last add, for instance. */
-
- if (events & (EV_READ|EV_SIGNAL)) {
- change->read_change = EV_CHANGE_ADD |
- (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
- }
- if (events & EV_WRITE) {
- change->write_change = EV_CHANGE_ADD |
- (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
- }
- if (events & EV_CLOSED) {
- change->close_change = EV_CHANGE_ADD |
- (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
- }
-
- event_changelist_check(base);
- return (0);
-}
-
-int
-event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
- void *p)
-{
- struct event_changelist *changelist = &base->changelist;
- struct event_changelist_fdinfo *fdinfo = p;
- struct event_change *change;
-
- event_changelist_check(base);
- change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
- event_changelist_check(base);
- if (!change)
- return -1;
-
- /* A delete on an event set that doesn't contain the event to be
- deleted produces a no-op. This effectively emoves any previous
- uncommitted add, rather than replacing it: on those platforms where
- "add, delete, dispatch" is not the same as "no-op, dispatch", we
- want the no-op behavior.
-
- If we have a no-op item, we could remove it it from the list
- entirely, but really there's not much point: skipping the no-op
- change when we do the dispatch later is far cheaper than rejuggling
- the array now.
-
- As this stands, it also lets through deletions of events that are
- not currently set.
- */
-
- if (events & (EV_READ|EV_SIGNAL)) {
- if (!(change->old_events & (EV_READ | EV_SIGNAL)))
- change->read_change = 0;
- else
- change->read_change = EV_CHANGE_DEL;
- }
- if (events & EV_WRITE) {
- if (!(change->old_events & EV_WRITE))
- change->write_change = 0;
- else
- change->write_change = EV_CHANGE_DEL;
- }
- if (events & EV_CLOSED) {
- if (!(change->old_events & EV_CLOSED))
- change->close_change = 0;
- else
- change->close_change = EV_CHANGE_DEL;
- }
-
- event_changelist_check(base);
- return (0);
-}
-
-/* Helper for evmap_check_integrity_: verify that all of the events pending on
- * given fd are set up correctly, and that the nread and nwrite counts on that
- * fd are correct. */
-static int
-evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
- struct evmap_io *io_info, void *arg)
-{
- struct event *ev;
- int n_read = 0, n_write = 0, n_close = 0;
-
- /* First, make sure the list itself isn't corrupt. Otherwise,
- * running LIST_FOREACH could be an exciting adventure. */
- EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
-
- LIST_FOREACH(ev, &io_info->events, ev_io_next) {
- EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
- EVUTIL_ASSERT(ev->ev_fd == fd);
- EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
- EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
- if (ev->ev_events & EV_READ)
- ++n_read;
- if (ev->ev_events & EV_WRITE)
- ++n_write;
- if (ev->ev_events & EV_CLOSED)
- ++n_close;
- }
-
- EVUTIL_ASSERT(n_read == io_info->nread);
- EVUTIL_ASSERT(n_write == io_info->nwrite);
- EVUTIL_ASSERT(n_close == io_info->nclose);
-
- return 0;
-}
-
-/* Helper for evmap_check_integrity_: verify that all of the events pending
- * on given signal are set up correctly. */
-static int
-evmap_signal_check_integrity_fn(struct event_base *base,
- int signum, struct evmap_signal *sig_info, void *arg)
-{
- struct event *ev;
- /* First, make sure the list itself isn't corrupt. */
- EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
-
- LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
- EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
- EVUTIL_ASSERT(ev->ev_fd == signum);
- EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
- EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
- }
- return 0;
-}
-
-void
-evmap_check_integrity_(struct event_base *base)
-{
- evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
- evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
-
- if (base->evsel->add == event_changelist_add_)
- event_changelist_assert_ok(base);
-}
-
-/* Helper type for evmap_foreach_event_: Bundles a function to call on every
- * event, and the user-provided void* to use as its third argument. */
-struct evmap_foreach_event_helper {
- event_base_foreach_event_cb fn;
- void *arg;
-};
-
-/* Helper for evmap_foreach_event_: calls a provided function on every event
- * pending on a given fd. */
-static int
-evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
- struct evmap_io *io_info, void *arg)
-{
- struct evmap_foreach_event_helper *h = arg;
- struct event *ev;
- int r;
- LIST_FOREACH(ev, &io_info->events, ev_io_next) {
- if ((r = h->fn(base, ev, h->arg)))
- return r;
- }
- return 0;
-}
-
-/* Helper for evmap_foreach_event_: calls a provided function on every event
- * pending on a given signal. */
-static int
-evmap_signal_foreach_event_fn(struct event_base *base, int signum,
- struct evmap_signal *sig_info, void *arg)
-{
- struct event *ev;
- struct evmap_foreach_event_helper *h = arg;
- int r;
- LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
- if ((r = h->fn(base, ev, h->arg)))
- return r;
- }
- return 0;
-}
-
-int
-evmap_foreach_event_(struct event_base *base,
- event_base_foreach_event_cb fn, void *arg)
-{
- struct evmap_foreach_event_helper h;
- int r;
- h.fn = fn;
- h.arg = arg;
- if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
- return r;
- return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
-}
-
diff --git a/libs/libevent/src/evrpc-internal.h b/libs/libevent/src/evrpc-internal.h
deleted file mode 100644
index 9eb376386d..0000000000
--- a/libs/libevent/src/evrpc-internal.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (c) 2006-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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_INCLUDED_
-#define EVRPC_INTERNAL_H_INCLUDED_
-
-#include "event2/http.h"
-#include "http-internal.h"
-
-struct evrpc;
-struct evrpc_request_wrapper;
-
-#define EVRPC_URI_PREFIX "/.rpc."
-
-struct evrpc_hook {
- TAILQ_ENTRY(evrpc_hook) next;
-
- /* returns EVRPC_TERMINATE; if the rpc should be aborted.
- * a hook is is allowed to rewrite the evbuffer
- */
- int (*process)(void *, 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_hook_ctx;
-TAILQ_HEAD(evrpc_pause_list, evrpc_hook_ctx);
-
-struct evrpc_hooks_ {
- /* hooks for processing outbound and inbound rpcs */
- struct evrpc_hook_list in_hooks;
- struct evrpc_hook_list out_hooks;
-
- struct evrpc_pause_list pause_requests;
-};
-
-#define input_hooks common.in_hooks
-#define output_hooks common.out_hooks
-#define paused_requests common.pause_requests
-
-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);
-};
-
-struct evrpc_hook_ctx {
- TAILQ_ENTRY(evrpc_hook_ctx) next;
-
- void *ctx;
- void (*cb)(void *, enum EVRPC_HOOK_RESULT);
-};
-
-struct evrpc_meta {
- TAILQ_ENTRY(evrpc_meta) next;
- char *key;
-
- void *data;
- size_t data_size;
-};
-
-TAILQ_HEAD(evrpc_meta_list, evrpc_meta);
-
-struct evrpc_hook_meta {
- struct evrpc_meta_list meta_data;
- struct evhttp_connection *evcon;
-};
-
-/* allows association of meta data with a request */
-static void evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx,
- struct evhttp_connection *evcon);
-
-/* creates a new meta data store */
-static struct evrpc_hook_meta *evrpc_hook_meta_new_(void);
-
-/* frees the meta data associated with a request */
-static void evrpc_hook_context_free_(struct evrpc_hook_meta *ctx);
-
-/* the server side of an rpc */
-
-/* We alias the RPC specific structs to this voided one */
-struct evrpc_req_generic {
- /*
- * allows association of meta data via hooks - needs to be
- * synchronized with evrpc_request_wrapper
- */
- struct evrpc_hook_meta *hook_meta;
-
- /* 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;
-
- /*
- * Temporary data store for marshaled data
- */
- struct evbuffer* rpc_data;
-};
-
-/* the client side of an rpc request */
-struct evrpc_request_wrapper {
- /*
- * allows association of meta data via hooks - needs to be
- * synchronized with evrpc_req_generic.
- */
- struct evrpc_hook_meta *hook_meta;
-
- 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;
-
- /* the actual request */
- struct evhttp_request *req;
-
- /* 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*);
-};
-
-#endif /* EVRPC_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/evrpc.c b/libs/libevent/src/evrpc.c
deleted file mode 100644
index 2443ab2793..0000000000
--- a/libs/libevent/src/evrpc.c
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#endif
-
-#include <sys/types.h>
-#ifndef _WIN32
-#include <sys/socket.h>
-#endif
-#ifdef EVENT__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 <sys/queue.h>
-
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "event2/rpc.h"
-#include "event2/rpc_struct.h"
-#include "evrpc-internal.h"
-#include "event2/http.h"
-#include "event2/buffer.h"
-#include "event2/tag.h"
-#include "event2/http_struct.h"
-#include "event2/http_compat.h"
-#include "event2/util.h"
-#include "util-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-
-struct evrpc_base *
-evrpc_init(struct evhttp *http_server)
-{
- struct evrpc_base* base = mm_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);
-
- TAILQ_INIT(&base->paused_requests);
-
- base->http_server = http_server;
-
- return (base);
-}
-
-void
-evrpc_free(struct evrpc_base *base)
-{
- struct evrpc *rpc;
- struct evrpc_hook *hook;
- struct evrpc_hook_ctx *pause;
- int r;
-
- while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
- r = evrpc_unregister_rpc(base, rpc->uri);
- EVUTIL_ASSERT(r == 0);
- }
- while ((pause = TAILQ_FIRST(&base->paused_requests)) != NULL) {
- TAILQ_REMOVE(&base->paused_requests, pause, next);
- mm_free(pause);
- }
- while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
- r = evrpc_remove_hook(base, EVRPC_INPUT, hook);
- EVUTIL_ASSERT(r);
- }
- while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
- r = evrpc_remove_hook(base, EVRPC_OUTPUT, hook);
- EVUTIL_ASSERT(r);
- }
- mm_free(base);
-}
-
-void *
-evrpc_add_hook(void *vbase,
- enum EVRPC_HOOK_TYPE hook_type,
- int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
- void *cb_arg)
-{
- struct evrpc_hooks_ *base = vbase;
- struct evrpc_hook_list *head = NULL;
- struct evrpc_hook *hook = NULL;
- switch (hook_type) {
- case EVRPC_INPUT:
- head = &base->in_hooks;
- break;
- case EVRPC_OUTPUT:
- head = &base->out_hooks;
- break;
- default:
- EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
- }
-
- hook = mm_calloc(1, sizeof(struct evrpc_hook));
- EVUTIL_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);
- mm_free(hook);
- return (1);
- }
- }
-
- return (0);
-}
-
-/*
- * remove the hook specified by the handle
- */
-
-int
-evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
-{
- struct evrpc_hooks_ *base = vbase;
- struct evrpc_hook_list *head = NULL;
- switch (hook_type) {
- case EVRPC_INPUT:
- head = &base->in_hooks;
- break;
- case EVRPC_OUTPUT:
- head = &base->out_hooks;
- break;
- default:
- EVUTIL_ASSERT(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
- }
-
- return (evrpc_remove_hook_internal(head, handle));
-}
-
-static int
-evrpc_process_hooks(struct evrpc_hook_list *head, void *ctx,
- struct evhttp_request *req, struct evbuffer *evbuf)
-{
- struct evrpc_hook *hook;
- TAILQ_FOREACH(hook, head, next) {
- int res = hook->process(ctx, req, evbuf, hook->process_arg);
- if (res != EVRPC_CONTINUE)
- return (res);
- }
-
- return (EVRPC_CONTINUE);
-}
-
-static void evrpc_pool_schedule(struct evrpc_pool *pool);
-static void evrpc_request_cb(struct evhttp_request *, void *);
-
-/*
- * 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;
- size_t constructed_uri_len;
-
- constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
- if ((constructed_uri = mm_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);
-
- mm_free(constructed_uri);
-
- return (0);
-}
-
-int
-evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
-{
- char *registered_uri = NULL;
- struct evrpc *rpc;
- int r;
-
- /* 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);
-
- registered_uri = evrpc_construct_uri(name);
-
- /* remove the http server callback */
- r = evhttp_del_cb(base->http_server, registered_uri);
- EVUTIL_ASSERT(r == 0);
-
- mm_free(registered_uri);
-
- mm_free((char *)rpc->uri);
- mm_free(rpc);
- return (0);
-}
-
-static int evrpc_pause_request(void *vbase, void *ctx,
- void (*cb)(void *, enum EVRPC_HOOK_RESULT));
-static void evrpc_request_cb_closure(void *, enum EVRPC_HOOK_RESULT);
-
-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_get_length(req->input_buffer) <= 0)
- goto error;
-
- rpc_state = mm_calloc(1, sizeof(struct evrpc_req_generic));
- if (rpc_state == NULL)
- goto error;
- rpc_state->rpc = rpc;
- rpc_state->http_req = req;
- rpc_state->rpc_data = NULL;
-
- if (TAILQ_FIRST(&rpc->base->input_hooks) != NULL) {
- int hook_res;
-
- evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
-
- /*
- * allow hooks to modify the outgoing request
- */
- hook_res = evrpc_process_hooks(&rpc->base->input_hooks,
- rpc_state, req, req->input_buffer);
- switch (hook_res) {
- case EVRPC_TERMINATE:
- goto error;
- case EVRPC_PAUSE:
- evrpc_pause_request(rpc->base, rpc_state,
- evrpc_request_cb_closure);
- return;
- case EVRPC_CONTINUE:
- break;
- default:
- EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
- hook_res == EVRPC_CONTINUE ||
- hook_res == EVRPC_PAUSE);
- }
- }
-
- evrpc_request_cb_closure(rpc_state, EVRPC_CONTINUE);
- return;
-
-error:
- evrpc_reqstate_free_(rpc_state);
- evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
- return;
-}
-
-static void
-evrpc_request_cb_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
-{
- struct evrpc_req_generic *rpc_state = arg;
- struct evrpc *rpc;
- struct evhttp_request *req;
-
- EVUTIL_ASSERT(rpc_state);
- rpc = rpc_state->rpc;
- req = rpc_state->http_req;
-
- if (hook_res == EVRPC_TERMINATE)
- goto error;
-
- /* let's check that we can parse the request */
- rpc_state->request = rpc->request_new(rpc->request_new_arg);
- if (rpc_state->request == NULL)
- goto error;
-
- 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(rpc->reply_new_arg);
- if (rpc_state->reply == NULL)
- goto error;
-
- /* 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, NULL);
- return;
-}
-
-
-void
-evrpc_reqstate_free_(struct evrpc_req_generic* rpc_state)
-{
- struct evrpc *rpc;
- EVUTIL_ASSERT(rpc_state != NULL);
- rpc = rpc_state->rpc;
-
- /* clean up all memory */
- if (rpc_state->hook_meta != NULL)
- evrpc_hook_context_free_(rpc_state->hook_meta);
- if (rpc_state->request != NULL)
- rpc->request_free(rpc_state->request);
- if (rpc_state->reply != NULL)
- rpc->reply_free(rpc_state->reply);
- if (rpc_state->rpc_data != NULL)
- evbuffer_free(rpc_state->rpc_data);
- mm_free(rpc_state);
-}
-
-static void
-evrpc_request_done_closure(void *, enum EVRPC_HOOK_RESULT);
-
-void
-evrpc_request_done(struct evrpc_req_generic *rpc_state)
-{
- struct evhttp_request *req;
- struct evrpc *rpc;
-
- EVUTIL_ASSERT(rpc_state);
-
- req = rpc_state->http_req;
- rpc = rpc_state->rpc;
-
- if (rpc->reply_complete(rpc_state->reply) == -1) {
- /* the reply was not completely filled in. error out */
- goto error;
- }
-
- if ((rpc_state->rpc_data = evbuffer_new()) == NULL) {
- /* out of memory */
- goto error;
- }
-
- /* serialize the reply */
- rpc->reply_marshal(rpc_state->rpc_data, rpc_state->reply);
-
- if (TAILQ_FIRST(&rpc->base->output_hooks) != NULL) {
- int hook_res;
-
- evrpc_hook_associate_meta_(&rpc_state->hook_meta, req->evcon);
-
- /* do hook based tweaks to the request */
- hook_res = evrpc_process_hooks(&rpc->base->output_hooks,
- rpc_state, req, rpc_state->rpc_data);
- switch (hook_res) {
- case EVRPC_TERMINATE:
- goto error;
- case EVRPC_PAUSE:
- if (evrpc_pause_request(rpc->base, rpc_state,
- evrpc_request_done_closure) == -1)
- goto error;
- return;
- case EVRPC_CONTINUE:
- break;
- default:
- EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
- hook_res == EVRPC_CONTINUE ||
- hook_res == EVRPC_PAUSE);
- }
- }
-
- evrpc_request_done_closure(rpc_state, EVRPC_CONTINUE);
- return;
-
-error:
- evrpc_reqstate_free_(rpc_state);
- evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
- return;
-}
-
-void *
-evrpc_get_request(struct evrpc_req_generic *req)
-{
- return req->request;
-}
-
-void *
-evrpc_get_reply(struct evrpc_req_generic *req)
-{
- return req->reply;
-}
-
-static void
-evrpc_request_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
-{
- struct evrpc_req_generic *rpc_state = arg;
- struct evhttp_request *req;
- EVUTIL_ASSERT(rpc_state);
- req = rpc_state->http_req;
-
- if (hook_res == EVRPC_TERMINATE)
- 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", rpc_state->rpc_data);
-
- evrpc_reqstate_free_(rpc_state);
-
- return;
-
-error:
- evrpc_reqstate_free_(rpc_state);
- evhttp_send_error(req, HTTP_SERVUNAVAIL, NULL);
- 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 = mm_calloc(1, sizeof(struct evrpc_pool));
- if (pool == NULL)
- return (NULL);
-
- TAILQ_INIT(&pool->connections);
- TAILQ_INIT(&pool->requests);
-
- TAILQ_INIT(&pool->paused_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)
-{
- if (request->hook_meta != NULL)
- evrpc_hook_context_free_(request->hook_meta);
- mm_free(request->name);
- mm_free(request);
-}
-
-void
-evrpc_pool_free(struct evrpc_pool *pool)
-{
- struct evhttp_connection *connection;
- struct evrpc_request_wrapper *request;
- struct evrpc_hook_ctx *pause;
- struct evrpc_hook *hook;
- int r;
-
- while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
- TAILQ_REMOVE(&pool->requests, request, next);
- evrpc_request_wrapper_free(request);
- }
-
- while ((pause = TAILQ_FIRST(&pool->paused_requests)) != NULL) {
- TAILQ_REMOVE(&pool->paused_requests, pause, next);
- mm_free(pause);
- }
-
- 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) {
- r = evrpc_remove_hook(pool, EVRPC_INPUT, hook);
- EVUTIL_ASSERT(r);
- }
-
- while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
- r = evrpc_remove_hook(pool, EVRPC_OUTPUT, hook);
- EVUTIL_ASSERT(r);
- }
-
- mm_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)
-{
- EVUTIL_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 (!evutil_timerisset(&connection->timeout))
- evhttp_connection_set_timeout(connection, 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_remove_connection(struct evrpc_pool *pool,
- struct evhttp_connection *connection)
-{
- TAILQ_REMOVE(&pool->connections, connection, next);
-}
-
-void
-evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
-{
- struct evhttp_connection *evcon;
- TAILQ_FOREACH(evcon, &pool->connections, next) {
- evhttp_connection_set_timeout(evcon, timeout_in_secs);
- }
- pool->timeout = timeout_in_secs;
-}
-
-
-static void evrpc_reply_done(struct evhttp_request *, void *);
-static void evrpc_request_timeout(evutil_socket_t, 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);
-}
-
-/*
- * Prototypes responsible for evrpc scheduling and hooking
- */
-
-static void evrpc_schedule_request_closure(void *ctx, enum EVRPC_HOOK_RESULT);
-
-/*
- * 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;
-
- 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);
-
- /* we need to know the connection that we might have to abort */
- ctx->evcon = connection;
-
- /* if we get paused we also need to know the request */
- ctx->req = req;
-
- if (TAILQ_FIRST(&pool->output_hooks) != NULL) {
- int hook_res;
-
- evrpc_hook_associate_meta_(&ctx->hook_meta, connection);
-
- /* apply hooks to the outgoing request */
- hook_res = evrpc_process_hooks(&pool->output_hooks,
- ctx, req, req->output_buffer);
-
- switch (hook_res) {
- case EVRPC_TERMINATE:
- goto error;
- case EVRPC_PAUSE:
- /* we need to be explicitly resumed */
- if (evrpc_pause_request(pool, ctx,
- evrpc_schedule_request_closure) == -1)
- goto error;
- return (0);
- case EVRPC_CONTINUE:
- /* we can just continue */
- break;
- default:
- EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
- hook_res == EVRPC_CONTINUE ||
- hook_res == EVRPC_PAUSE);
- }
- }
-
- evrpc_schedule_request_closure(ctx, EVRPC_CONTINUE);
- 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);
-}
-
-static void
-evrpc_schedule_request_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
-{
- struct evrpc_request_wrapper *ctx = arg;
- struct evhttp_connection *connection = ctx->evcon;
- struct evhttp_request *req = ctx->req;
- struct evrpc_pool *pool = ctx->pool;
- struct evrpc_status status;
- char *uri = NULL;
- int res = 0;
-
- if (hook_res == EVRPC_TERMINATE)
- goto error;
-
- uri = evrpc_construct_uri(ctx->name);
- if (uri == NULL)
- 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);
- mm_free(uri);
-
- if (res == -1)
- goto error;
-
- return;
-
-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);
-}
-
-/* we just queue the paused request on the pool under the req object */
-static int
-evrpc_pause_request(void *vbase, void *ctx,
- void (*cb)(void *, enum EVRPC_HOOK_RESULT))
-{
- struct evrpc_hooks_ *base = vbase;
- struct evrpc_hook_ctx *pause = mm_malloc(sizeof(*pause));
- if (pause == NULL)
- return (-1);
-
- pause->ctx = ctx;
- pause->cb = cb;
-
- TAILQ_INSERT_TAIL(&base->pause_requests, pause, next);
- return (0);
-}
-
-int
-evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res)
-{
- struct evrpc_hooks_ *base = vbase;
- struct evrpc_pause_list *head = &base->pause_requests;
- struct evrpc_hook_ctx *pause;
-
- TAILQ_FOREACH(pause, head, next) {
- if (pause->ctx == ctx)
- break;
- }
-
- if (pause == NULL)
- return (-1);
-
- (*pause->cb)(pause->ctx, res);
- TAILQ_REMOVE(head, pause, next);
- mm_free(pause);
- return (0);
-}
-
-int
-evrpc_make_request(struct evrpc_request_wrapper *ctx)
-{
- struct evrpc_pool *pool = ctx->pool;
-
- /* initialize the event structure for this rpc */
- evtimer_assign(&ctx->ev_timeout, pool->base, evrpc_request_timeout, ctx);
-
- /* we better have some available connections on the pool */
- EVUTIL_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);
-}
-
-
-struct evrpc_request_wrapper *
-evrpc_make_request_ctx(
- struct evrpc_pool *pool, void *request, void *reply,
- const char *rpcname,
- void (*req_marshal)(struct evbuffer*, void *),
- void (*rpl_clear)(void *),
- int (*rpl_unmarshal)(void *, struct evbuffer *),
- void (*cb)(struct evrpc_status *, void *, void *, void *),
- void *cbarg)
-{
- struct evrpc_request_wrapper *ctx = (struct evrpc_request_wrapper *)
- mm_malloc(sizeof(struct evrpc_request_wrapper));
- if (ctx == NULL)
- return (NULL);
-
- ctx->pool = pool;
- ctx->hook_meta = NULL;
- ctx->evcon = NULL;
- ctx->name = mm_strdup(rpcname);
- if (ctx->name == NULL) {
- mm_free(ctx);
- return (NULL);
- }
- ctx->cb = cb;
- ctx->cb_arg = cbarg;
- ctx->request = request;
- ctx->reply = reply;
- ctx->request_marshal = req_marshal;
- ctx->reply_clear = rpl_clear;
- ctx->reply_unmarshal = rpl_unmarshal;
-
- return (ctx);
-}
-
-static void
-evrpc_reply_done_closure(void *, enum EVRPC_HOOK_RESULT);
-
-static void
-evrpc_reply_done(struct evhttp_request *req, void *arg)
-{
- struct evrpc_request_wrapper *ctx = arg;
- struct evrpc_pool *pool = ctx->pool;
- int hook_res = EVRPC_CONTINUE;
-
- /* cancel any timeout we might have scheduled */
- event_del(&ctx->ev_timeout);
-
- ctx->req = req;
-
- /* we need to get the reply now */
- if (req == NULL) {
- evrpc_reply_done_closure(ctx, EVRPC_CONTINUE);
- return;
- }
-
- if (TAILQ_FIRST(&pool->input_hooks) != NULL) {
- evrpc_hook_associate_meta_(&ctx->hook_meta, ctx->evcon);
-
- /* apply hooks to the incoming request */
- hook_res = evrpc_process_hooks(&pool->input_hooks,
- ctx, req, req->input_buffer);
-
- switch (hook_res) {
- case EVRPC_TERMINATE:
- case EVRPC_CONTINUE:
- break;
- case EVRPC_PAUSE:
- /*
- * if we get paused we also need to know the
- * request. unfortunately, the underlying
- * layer is going to free it. we need to
- * request ownership explicitly
- */
- if (req != NULL)
- evhttp_request_own(req);
-
- evrpc_pause_request(pool, ctx,
- evrpc_reply_done_closure);
- return;
- default:
- EVUTIL_ASSERT(hook_res == EVRPC_TERMINATE ||
- hook_res == EVRPC_CONTINUE ||
- hook_res == EVRPC_PAUSE);
- }
- }
-
- evrpc_reply_done_closure(ctx, hook_res);
-
- /* http request is being freed by underlying layer */
-}
-
-static void
-evrpc_reply_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
-{
- struct evrpc_request_wrapper *ctx = arg;
- struct evhttp_request *req = ctx->req;
- struct evrpc_pool *pool = ctx->pool;
- struct evrpc_status status;
- int res = -1;
-
- memset(&status, 0, sizeof(status));
- status.http_req = req;
-
- /* we need to get the reply now */
- if (req == NULL) {
- status.error = EVRPC_STATUS_ERR_TIMEOUT;
- } else if (hook_res == EVRPC_TERMINATE) {
- status.error = EVRPC_STATUS_ERR_HOOKABORTED;
- } else {
- res = ctx->reply_unmarshal(ctx->reply, req->input_buffer);
- if (res == -1)
- status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
- }
-
- 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 owned the original request structure, but if we
- * got paused, we asked for ownership and need to free it here. */
- if (req != NULL && evhttp_request_is_owned(req))
- evhttp_request_free(req);
-
- /* 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(evutil_socket_t fd, short what, void *arg)
-{
- struct evrpc_request_wrapper *ctx = arg;
- struct evhttp_connection *evcon = ctx->evcon;
- EVUTIL_ASSERT(evcon != NULL);
-
- evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
-}
-
-/*
- * frees potential meta data associated with a request.
- */
-
-static void
-evrpc_meta_data_free(struct evrpc_meta_list *meta_data)
-{
- struct evrpc_meta *entry;
- EVUTIL_ASSERT(meta_data != NULL);
-
- while ((entry = TAILQ_FIRST(meta_data)) != NULL) {
- TAILQ_REMOVE(meta_data, entry, next);
- mm_free(entry->key);
- mm_free(entry->data);
- mm_free(entry);
- }
-}
-
-static struct evrpc_hook_meta *
-evrpc_hook_meta_new_(void)
-{
- struct evrpc_hook_meta *ctx;
- ctx = mm_malloc(sizeof(struct evrpc_hook_meta));
- EVUTIL_ASSERT(ctx != NULL);
-
- TAILQ_INIT(&ctx->meta_data);
- ctx->evcon = NULL;
-
- return (ctx);
-}
-
-static void
-evrpc_hook_associate_meta_(struct evrpc_hook_meta **pctx,
- struct evhttp_connection *evcon)
-{
- struct evrpc_hook_meta *ctx = *pctx;
- if (ctx == NULL)
- *pctx = ctx = evrpc_hook_meta_new_();
- ctx->evcon = evcon;
-}
-
-static void
-evrpc_hook_context_free_(struct evrpc_hook_meta *ctx)
-{
- evrpc_meta_data_free(&ctx->meta_data);
- mm_free(ctx);
-}
-
-/* Adds meta data */
-void
-evrpc_hook_add_meta(void *ctx, const char *key,
- const void *data, size_t data_size)
-{
- struct evrpc_request_wrapper *req = ctx;
- struct evrpc_hook_meta *store = NULL;
- struct evrpc_meta *meta = NULL;
-
- if ((store = req->hook_meta) == NULL)
- store = req->hook_meta = evrpc_hook_meta_new_();
-
- meta = mm_malloc(sizeof(struct evrpc_meta));
- EVUTIL_ASSERT(meta != NULL);
- meta->key = mm_strdup(key);
- EVUTIL_ASSERT(meta->key != NULL);
- meta->data_size = data_size;
- meta->data = mm_malloc(data_size);
- EVUTIL_ASSERT(meta->data != NULL);
- memcpy(meta->data, data, data_size);
-
- TAILQ_INSERT_TAIL(&store->meta_data, meta, next);
-}
-
-int
-evrpc_hook_find_meta(void *ctx, const char *key, void **data, size_t *data_size)
-{
- struct evrpc_request_wrapper *req = ctx;
- struct evrpc_meta *meta = NULL;
-
- if (req->hook_meta == NULL)
- return (-1);
-
- TAILQ_FOREACH(meta, &req->hook_meta->meta_data, next) {
- if (strcmp(meta->key, key) == 0) {
- *data = meta->data;
- *data_size = meta->data_size;
- return (0);
- }
- }
-
- return (-1);
-}
-
-struct evhttp_connection *
-evrpc_hook_get_connection(void *ctx)
-{
- struct evrpc_request_wrapper *req = ctx;
- return (req->hook_meta != NULL ? req->hook_meta->evcon : NULL);
-}
-
-int
-evrpc_send_request_generic(struct evrpc_pool *pool,
- void *request, void *reply,
- void (*cb)(struct evrpc_status *, void *, void *, void *),
- void *cb_arg,
- const char *rpcname,
- void (*req_marshal)(struct evbuffer *, void *),
- void (*rpl_clear)(void *),
- int (*rpl_unmarshal)(void *, struct evbuffer *))
-{
- struct evrpc_status status;
- struct evrpc_request_wrapper *ctx;
- ctx = evrpc_make_request_ctx(pool, request, reply,
- rpcname, req_marshal, rpl_clear, rpl_unmarshal, cb, cb_arg);
- if (ctx == NULL)
- goto error;
- return (evrpc_make_request(ctx));
-error:
- memset(&status, 0, sizeof(status));
- status.error = EVRPC_STATUS_ERR_UNSTARTED;
- (*(cb))(&status, request, reply, cb_arg);
- return (-1);
-}
-
-/** Takes a request object and fills it in with the right magic */
-static struct evrpc *
-evrpc_register_object(const char *name,
- void *(*req_new)(void*), void *req_new_arg, void (*req_free)(void *),
- int (*req_unmarshal)(void *, struct evbuffer *),
- void *(*rpl_new)(void*), void *rpl_new_arg, void (*rpl_free)(void *),
- int (*rpl_complete)(void *),
- void (*rpl_marshal)(struct evbuffer *, void *))
-{
- struct evrpc* rpc = (struct evrpc *)mm_calloc(1, sizeof(struct evrpc));
- if (rpc == NULL)
- return (NULL);
- rpc->uri = mm_strdup(name);
- if (rpc->uri == NULL) {
- mm_free(rpc);
- return (NULL);
- }
- rpc->request_new = req_new;
- rpc->request_new_arg = req_new_arg;
- rpc->request_free = req_free;
- rpc->request_unmarshal = req_unmarshal;
- rpc->reply_new = rpl_new;
- rpc->reply_new_arg = rpl_new_arg;
- rpc->reply_free = rpl_free;
- rpc->reply_complete = rpl_complete;
- rpc->reply_marshal = rpl_marshal;
- return (rpc);
-}
-
-int
-evrpc_register_generic(struct evrpc_base *base, const char *name,
- void (*callback)(struct evrpc_req_generic *, void *), void *cbarg,
- void *(*req_new)(void *), void *req_new_arg, void (*req_free)(void *),
- int (*req_unmarshal)(void *, struct evbuffer *),
- void *(*rpl_new)(void *), void *rpl_new_arg, void (*rpl_free)(void *),
- int (*rpl_complete)(void *),
- void (*rpl_marshal)(struct evbuffer *, void *))
-{
- struct evrpc* rpc =
- evrpc_register_object(name, req_new, req_new_arg, req_free, req_unmarshal,
- rpl_new, rpl_new_arg, rpl_free, rpl_complete, rpl_marshal);
- if (rpc == NULL)
- return (-1);
- evrpc_register_rpc(base, rpc,
- (void (*)(struct evrpc_req_generic*, void *))callback, cbarg);
- return (0);
-}
-
-/** accessors for obscure and undocumented functionality */
-struct evrpc_pool *
-evrpc_request_get_pool(struct evrpc_request_wrapper *ctx)
-{
- return (ctx->pool);
-}
-
-void
-evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
- struct evrpc_pool *pool)
-{
- ctx->pool = pool;
-}
-
-void
-evrpc_request_set_cb(struct evrpc_request_wrapper *ctx,
- void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg),
- void *cb_arg)
-{
- ctx->cb = cb;
- ctx->cb_arg = cb_arg;
-}
diff --git a/libs/libevent/src/evsignal-internal.h b/libs/libevent/src/evsignal-internal.h
deleted file mode 100644
index 5cff03b525..0000000000
--- a/libs/libevent/src/evsignal-internal.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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_INTERNAL_H_INCLUDED_
-#define EVSIGNAL_INTERNAL_H_INCLUDED_
-
-#ifndef evutil_socket_t
-#include "event2/util.h"
-#endif
-#include <signal.h>
-
-typedef void (*ev_sighandler_t)(int);
-
-/* Data structure for the default signal-handling implementation in signal.c
- */
-struct evsig_info {
- /* Event watching ev_signal_pair[1] */
- struct event ev_signal;
- /* Socketpair used to send notifications from the signal handler */
- evutil_socket_t ev_signal_pair[2];
- /* True iff we've added the ev_signal event yet. */
- int ev_signal_added;
- /* Count of the number of signals we're currently watching. */
- int ev_n_signals_added;
-
- /* Array of previous signal handler objects before Libevent started
- * messing with them. Used to restore old signal handlers. */
-#ifdef EVENT__HAVE_SIGACTION
- struct sigaction **sh_old;
-#else
- ev_sighandler_t **sh_old;
-#endif
- /* Size of sh_old. */
- int sh_old_max;
-};
-int evsig_init_(struct event_base *);
-void evsig_dealloc_(struct event_base *);
-
-void evsig_set_base_(struct event_base *base);
-void evsig_free_globals_(void);
-
-#endif /* EVSIGNAL_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/evthread-internal.h b/libs/libevent/src/evthread-internal.h
deleted file mode 100644
index efdecf81e7..0000000000
--- a/libs/libevent/src/evthread-internal.h
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
- *
- * 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 EVTHREAD_INTERNAL_H_INCLUDED_
-#define EVTHREAD_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include "event2/thread.h"
-#include "util-internal.h"
-
-struct event_base;
-
-#ifndef _WIN32
-/* On Windows, the way we currently make DLLs, it's not allowed for us to
- * have shared global structures. Thus, we only do the direct-call-to-function
- * code path if we know that the local shared library system supports it.
- */
-#define EVTHREAD_EXPOSE_STRUCTS
-#endif
-
-#if ! defined(EVENT__DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS)
-/* Global function pointers to lock-related functions. NULL if locking isn't
- enabled. */
-extern struct evthread_lock_callbacks evthread_lock_fns_;
-extern struct evthread_condition_callbacks evthread_cond_fns_;
-extern unsigned long (*evthread_id_fn_)(void);
-extern int evthread_lock_debugging_enabled_;
-
-/** Return the ID of the current thread, or 1 if threading isn't enabled. */
-#define EVTHREAD_GET_ID() \
- (evthread_id_fn_ ? evthread_id_fn_() : 1)
-
-/** Return true iff we're in the thread that is currently (or most recently)
- * running a given event_base's loop. Requires lock. */
-#define EVBASE_IN_THREAD(base) \
- (evthread_id_fn_ == NULL || \
- (base)->th_owner_id == evthread_id_fn_())
-
-/** Return true iff we need to notify the base's main thread about changes to
- * its state, because it's currently running the main loop in another
- * thread. Requires lock. */
-#define EVBASE_NEED_NOTIFY(base) \
- (evthread_id_fn_ != NULL && \
- (base)->running_loop && \
- (base)->th_owner_id != evthread_id_fn_())
-
-/** Allocate a new lock, and store it in lockvar, a void*. Sets lockvar to
- NULL if locking is not enabled. */
-#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \
- ((lockvar) = evthread_lock_fns_.alloc ? \
- evthread_lock_fns_.alloc(locktype) : NULL)
-
-/** Free a given lock, if it is present and locking is enabled. */
-#define EVTHREAD_FREE_LOCK(lockvar, locktype) \
- do { \
- void *lock_tmp_ = (lockvar); \
- if (lock_tmp_ && evthread_lock_fns_.free) \
- evthread_lock_fns_.free(lock_tmp_, (locktype)); \
- } while (0)
-
-/** Acquire a lock. */
-#define EVLOCK_LOCK(lockvar,mode) \
- do { \
- if (lockvar) \
- evthread_lock_fns_.lock(mode, lockvar); \
- } while (0)
-
-/** Release a lock */
-#define EVLOCK_UNLOCK(lockvar,mode) \
- do { \
- if (lockvar) \
- evthread_lock_fns_.unlock(mode, lockvar); \
- } while (0)
-
-/** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */
-#define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \
- do { \
- if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \
- void *tmp = lockvar1; \
- lockvar1 = lockvar2; \
- lockvar2 = tmp; \
- } \
- } while (0)
-
-/** Lock an event_base, if it is set up for locking. Acquires the lock
- in the base structure whose field is named 'lockvar'. */
-#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \
- EVLOCK_LOCK((base)->lockvar, 0); \
- } while (0)
-
-/** Unlock an event_base, if it is set up for locking. */
-#define EVBASE_RELEASE_LOCK(base, lockvar) do { \
- EVLOCK_UNLOCK((base)->lockvar, 0); \
- } while (0)
-
-/** If lock debugging is enabled, and lock is non-null, assert that 'lock' is
- * locked and held by us. */
-#define EVLOCK_ASSERT_LOCKED(lock) \
- do { \
- if ((lock) && evthread_lock_debugging_enabled_) { \
- EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \
- } \
- } while (0)
-
-/** Try to grab the lock for 'lockvar' without blocking, and return 1 if we
- * manage to get it. */
-static inline int EVLOCK_TRY_LOCK_(void *lock);
-static inline int
-EVLOCK_TRY_LOCK_(void *lock)
-{
- if (lock && evthread_lock_fns_.lock) {
- int r = evthread_lock_fns_.lock(EVTHREAD_TRY, lock);
- return !r;
- } else {
- /* Locking is disabled either globally or for this thing;
- * of course we count as having the lock. */
- return 1;
- }
-}
-
-/** Allocate a new condition variable and store it in the void *, condvar */
-#define EVTHREAD_ALLOC_COND(condvar) \
- do { \
- (condvar) = evthread_cond_fns_.alloc_condition ? \
- evthread_cond_fns_.alloc_condition(0) : NULL; \
- } while (0)
-/** Deallocate and free a condition variable in condvar */
-#define EVTHREAD_FREE_COND(cond) \
- do { \
- if (cond) \
- evthread_cond_fns_.free_condition((cond)); \
- } while (0)
-/** Signal one thread waiting on cond */
-#define EVTHREAD_COND_SIGNAL(cond) \
- ( (cond) ? evthread_cond_fns_.signal_condition((cond), 0) : 0 )
-/** Signal all threads waiting on cond */
-#define EVTHREAD_COND_BROADCAST(cond) \
- ( (cond) ? evthread_cond_fns_.signal_condition((cond), 1) : 0 )
-/** Wait until the condition 'cond' is signalled. Must be called while
- * holding 'lock'. The lock will be released until the condition is
- * signalled, at which point it will be acquired again. Returns 0 for
- * success, -1 for failure. */
-#define EVTHREAD_COND_WAIT(cond, lock) \
- ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), NULL) : 0 )
-/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1
- * on timeout. */
-#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \
- ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), (tv)) : 0 )
-
-/** True iff locking functions have been configured. */
-#define EVTHREAD_LOCKING_ENABLED() \
- (evthread_lock_fns_.lock != NULL)
-
-#elif ! defined(EVENT__DISABLE_THREAD_SUPPORT)
-
-unsigned long evthreadimpl_get_id_(void);
-int evthreadimpl_is_lock_debugging_enabled_(void);
-void *evthreadimpl_lock_alloc_(unsigned locktype);
-void evthreadimpl_lock_free_(void *lock, unsigned locktype);
-int evthreadimpl_lock_lock_(unsigned mode, void *lock);
-int evthreadimpl_lock_unlock_(unsigned mode, void *lock);
-void *evthreadimpl_cond_alloc_(unsigned condtype);
-void evthreadimpl_cond_free_(void *cond);
-int evthreadimpl_cond_signal_(void *cond, int broadcast);
-int evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv);
-int evthreadimpl_locking_enabled_(void);
-
-#define EVTHREAD_GET_ID() evthreadimpl_get_id_()
-#define EVBASE_IN_THREAD(base) \
- ((base)->th_owner_id == evthreadimpl_get_id_())
-#define EVBASE_NEED_NOTIFY(base) \
- ((base)->running_loop && \
- ((base)->th_owner_id != evthreadimpl_get_id_()))
-
-#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \
- ((lockvar) = evthreadimpl_lock_alloc_(locktype))
-
-#define EVTHREAD_FREE_LOCK(lockvar, locktype) \
- do { \
- void *lock_tmp_ = (lockvar); \
- if (lock_tmp_) \
- evthreadimpl_lock_free_(lock_tmp_, (locktype)); \
- } while (0)
-
-/** Acquire a lock. */
-#define EVLOCK_LOCK(lockvar,mode) \
- do { \
- if (lockvar) \
- evthreadimpl_lock_lock_(mode, lockvar); \
- } while (0)
-
-/** Release a lock */
-#define EVLOCK_UNLOCK(lockvar,mode) \
- do { \
- if (lockvar) \
- evthreadimpl_lock_unlock_(mode, lockvar); \
- } while (0)
-
-/** Lock an event_base, if it is set up for locking. Acquires the lock
- in the base structure whose field is named 'lockvar'. */
-#define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \
- EVLOCK_LOCK((base)->lockvar, 0); \
- } while (0)
-
-/** Unlock an event_base, if it is set up for locking. */
-#define EVBASE_RELEASE_LOCK(base, lockvar) do { \
- EVLOCK_UNLOCK((base)->lockvar, 0); \
- } while (0)
-
-/** If lock debugging is enabled, and lock is non-null, assert that 'lock' is
- * locked and held by us. */
-#define EVLOCK_ASSERT_LOCKED(lock) \
- do { \
- if ((lock) && evthreadimpl_is_lock_debugging_enabled_()) { \
- EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \
- } \
- } while (0)
-
-/** Try to grab the lock for 'lockvar' without blocking, and return 1 if we
- * manage to get it. */
-static inline int EVLOCK_TRY_LOCK_(void *lock);
-static inline int
-EVLOCK_TRY_LOCK_(void *lock)
-{
- if (lock) {
- int r = evthreadimpl_lock_lock_(EVTHREAD_TRY, lock);
- return !r;
- } else {
- /* Locking is disabled either globally or for this thing;
- * of course we count as having the lock. */
- return 1;
- }
-}
-
-/** Allocate a new condition variable and store it in the void *, condvar */
-#define EVTHREAD_ALLOC_COND(condvar) \
- do { \
- (condvar) = evthreadimpl_cond_alloc_(0); \
- } while (0)
-/** Deallocate and free a condition variable in condvar */
-#define EVTHREAD_FREE_COND(cond) \
- do { \
- if (cond) \
- evthreadimpl_cond_free_((cond)); \
- } while (0)
-/** Signal one thread waiting on cond */
-#define EVTHREAD_COND_SIGNAL(cond) \
- ( (cond) ? evthreadimpl_cond_signal_((cond), 0) : 0 )
-/** Signal all threads waiting on cond */
-#define EVTHREAD_COND_BROADCAST(cond) \
- ( (cond) ? evthreadimpl_cond_signal_((cond), 1) : 0 )
-/** Wait until the condition 'cond' is signalled. Must be called while
- * holding 'lock'. The lock will be released until the condition is
- * signalled, at which point it will be acquired again. Returns 0 for
- * success, -1 for failure. */
-#define EVTHREAD_COND_WAIT(cond, lock) \
- ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), NULL) : 0 )
-/** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1
- * on timeout. */
-#define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \
- ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), (tv)) : 0 )
-
-#define EVTHREAD_LOCKING_ENABLED() \
- (evthreadimpl_locking_enabled_())
-
-#else /* EVENT__DISABLE_THREAD_SUPPORT */
-
-#define EVTHREAD_GET_ID() 1
-#define EVTHREAD_ALLOC_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_
-#define EVTHREAD_FREE_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_
-
-#define EVLOCK_LOCK(lockvar, mode) EVUTIL_NIL_STMT_
-#define EVLOCK_UNLOCK(lockvar, mode) EVUTIL_NIL_STMT_
-#define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_
-#define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_
-
-#define EVBASE_IN_THREAD(base) 1
-#define EVBASE_NEED_NOTIFY(base) 0
-#define EVBASE_ACQUIRE_LOCK(base, lock) EVUTIL_NIL_STMT_
-#define EVBASE_RELEASE_LOCK(base, lock) EVUTIL_NIL_STMT_
-#define EVLOCK_ASSERT_LOCKED(lock) EVUTIL_NIL_STMT_
-
-#define EVLOCK_TRY_LOCK_(lock) 1
-
-#define EVTHREAD_ALLOC_COND(condvar) EVUTIL_NIL_STMT_
-#define EVTHREAD_FREE_COND(cond) EVUTIL_NIL_STMT_
-#define EVTHREAD_COND_SIGNAL(cond) EVUTIL_NIL_STMT_
-#define EVTHREAD_COND_BROADCAST(cond) EVUTIL_NIL_STMT_
-#define EVTHREAD_COND_WAIT(cond, lock) EVUTIL_NIL_STMT_
-#define EVTHREAD_COND_WAIT_TIMED(cond, lock, howlong) EVUTIL_NIL_STMT_
-
-#define EVTHREAD_LOCKING_ENABLED() 0
-
-#endif
-
-/* This code is shared between both lock impls */
-#if ! defined(EVENT__DISABLE_THREAD_SUPPORT)
-/** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */
-#define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \
- do { \
- if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \
- void *tmp = lockvar1; \
- lockvar1 = lockvar2; \
- lockvar2 = tmp; \
- } \
- } while (0)
-
-/** Acquire both lock1 and lock2. Always allocates locks in the same order,
- * so that two threads locking two locks with LOCK2 will not deadlock. */
-#define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) \
- do { \
- void *lock1_tmplock_ = (lock1); \
- void *lock2_tmplock_ = (lock2); \
- EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \
- EVLOCK_LOCK(lock1_tmplock_,mode1); \
- if (lock2_tmplock_ != lock1_tmplock_) \
- EVLOCK_LOCK(lock2_tmplock_,mode2); \
- } while (0)
-/** Release both lock1 and lock2. */
-#define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) \
- do { \
- void *lock1_tmplock_ = (lock1); \
- void *lock2_tmplock_ = (lock2); \
- EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \
- if (lock2_tmplock_ != lock1_tmplock_) \
- EVLOCK_UNLOCK(lock2_tmplock_,mode2); \
- EVLOCK_UNLOCK(lock1_tmplock_,mode1); \
- } while (0)
-
-int evthread_is_debug_lock_held_(void *lock);
-void *evthread_debug_get_real_lock_(void *lock);
-
-void *evthread_setup_global_lock_(void *lock_, unsigned locktype,
- int enable_locks);
-
-#define EVTHREAD_SETUP_GLOBAL_LOCK(lockvar, locktype) \
- do { \
- lockvar = evthread_setup_global_lock_(lockvar, \
- (locktype), enable_locks); \
- if (!lockvar) { \
- event_warn("Couldn't allocate %s", #lockvar); \
- return -1; \
- } \
- } while (0);
-
-int event_global_setup_locks_(const int enable_locks);
-int evsig_global_setup_locks_(const int enable_locks);
-int evutil_global_setup_locks_(const int enable_locks);
-int evutil_secure_rng_global_setup_locks_(const int enable_locks);
-
-/** Return current evthread_lock_callbacks */
-struct evthread_lock_callbacks *evthread_get_lock_callbacks(void);
-/** Return current evthread_condition_callbacks */
-struct evthread_condition_callbacks *evthread_get_condition_callbacks(void);
-/** Disable locking for internal usage (like global shutdown) */
-void evthreadimpl_disable_lock_debugging_(void);
-
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* EVTHREAD_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/evthread.c b/libs/libevent/src/evthread.c
deleted file mode 100644
index f3f1eddc89..0000000000
--- a/libs/libevent/src/evthread.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-
-#include "event2/thread.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "util-internal.h"
-#include "evthread-internal.h"
-
-#ifdef EVTHREAD_EXPOSE_STRUCTS
-#define GLOBAL
-#else
-#define GLOBAL static
-#endif
-
-#ifndef EVENT__DISABLE_DEBUG_MODE
-extern int event_debug_created_threadable_ctx_;
-extern int event_debug_mode_on_;
-#endif
-
-/* globals */
-GLOBAL int evthread_lock_debugging_enabled_ = 0;
-GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
- 0, 0, NULL, NULL, NULL, NULL
-};
-GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
-GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
- 0, NULL, NULL, NULL, NULL
-};
-
-/* Used for debugging */
-static struct evthread_lock_callbacks original_lock_fns_ = {
- 0, 0, NULL, NULL, NULL, NULL
-};
-static struct evthread_condition_callbacks original_cond_fns_ = {
- 0, NULL, NULL, NULL, NULL
-};
-
-void
-evthread_set_id_callback(unsigned long (*id_fn)(void))
-{
- evthread_id_fn_ = id_fn;
-}
-
-struct evthread_lock_callbacks *evthread_get_lock_callbacks()
-{
- return evthread_lock_debugging_enabled_
- ? &original_lock_fns_ : &evthread_lock_fns_;
-}
-struct evthread_condition_callbacks *evthread_get_condition_callbacks()
-{
- return evthread_lock_debugging_enabled_
- ? &original_cond_fns_ : &evthread_cond_fns_;
-}
-void evthreadimpl_disable_lock_debugging_(void)
-{
- evthread_lock_debugging_enabled_ = 0;
-}
-
-int
-evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
-{
- struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
-
-#ifndef EVENT__DISABLE_DEBUG_MODE
- if (event_debug_mode_on_) {
- if (event_debug_created_threadable_ctx_) {
- event_errx(1, "evthread initialization must be called BEFORE anything else!");
- }
- }
-#endif
-
- if (!cbs) {
- if (target->alloc)
- event_warnx("Trying to disable lock functions after "
- "they have been set up will probaby not work.");
- memset(target, 0, sizeof(evthread_lock_fns_));
- return 0;
- }
- if (target->alloc) {
- /* Uh oh; we already had locking callbacks set up.*/
- if (target->lock_api_version == cbs->lock_api_version &&
- target->supported_locktypes == cbs->supported_locktypes &&
- target->alloc == cbs->alloc &&
- target->free == cbs->free &&
- target->lock == cbs->lock &&
- target->unlock == cbs->unlock) {
- /* no change -- allow this. */
- return 0;
- }
- event_warnx("Can't change lock callbacks once they have been "
- "initialized.");
- return -1;
- }
- if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
- memcpy(target, cbs, sizeof(evthread_lock_fns_));
- return event_global_setup_locks_(1);
- } else {
- return -1;
- }
-}
-
-int
-evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
-{
- struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
-
-#ifndef EVENT__DISABLE_DEBUG_MODE
- if (event_debug_mode_on_) {
- if (event_debug_created_threadable_ctx_) {
- event_errx(1, "evthread initialization must be called BEFORE anything else!");
- }
- }
-#endif
-
- if (!cbs) {
- if (target->alloc_condition)
- event_warnx("Trying to disable condition functions "
- "after they have been set up will probaby not "
- "work.");
- memset(target, 0, sizeof(evthread_cond_fns_));
- return 0;
- }
- if (target->alloc_condition) {
- /* Uh oh; we already had condition callbacks set up.*/
- if (target->condition_api_version == cbs->condition_api_version &&
- target->alloc_condition == cbs->alloc_condition &&
- target->free_condition == cbs->free_condition &&
- target->signal_condition == cbs->signal_condition &&
- target->wait_condition == cbs->wait_condition) {
- /* no change -- allow this. */
- return 0;
- }
- event_warnx("Can't change condition callbacks once they "
- "have been initialized.");
- return -1;
- }
- if (cbs->alloc_condition && cbs->free_condition &&
- cbs->signal_condition && cbs->wait_condition) {
- memcpy(target, cbs, sizeof(evthread_cond_fns_));
- }
- if (evthread_lock_debugging_enabled_) {
- evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
- evthread_cond_fns_.free_condition = cbs->free_condition;
- evthread_cond_fns_.signal_condition = cbs->signal_condition;
- }
- return 0;
-}
-
-#define DEBUG_LOCK_SIG 0xdeb0b10c
-
-struct debug_lock {
- unsigned signature;
- unsigned locktype;
- unsigned long held_by;
- /* XXXX if we ever use read-write locks, we will need a separate
- * lock to protect count. */
- int count;
- void *lock;
-};
-
-static void *
-debug_lock_alloc(unsigned locktype)
-{
- struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
- if (!result)
- return NULL;
- if (original_lock_fns_.alloc) {
- if (!(result->lock = original_lock_fns_.alloc(
- locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
- mm_free(result);
- return NULL;
- }
- } else {
- result->lock = NULL;
- }
- result->signature = DEBUG_LOCK_SIG;
- result->locktype = locktype;
- result->count = 0;
- result->held_by = 0;
- return result;
-}
-
-static void
-debug_lock_free(void *lock_, unsigned locktype)
-{
- struct debug_lock *lock = lock_;
- EVUTIL_ASSERT(lock->count == 0);
- EVUTIL_ASSERT(locktype == lock->locktype);
- EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
- if (original_lock_fns_.free) {
- original_lock_fns_.free(lock->lock,
- lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
- }
- lock->lock = NULL;
- lock->count = -100;
- lock->signature = 0x12300fda;
- mm_free(lock);
-}
-
-static void
-evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
-{
- EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
- ++lock->count;
- if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
- EVUTIL_ASSERT(lock->count == 1);
- if (evthread_id_fn_) {
- unsigned long me;
- me = evthread_id_fn_();
- if (lock->count > 1)
- EVUTIL_ASSERT(lock->held_by == me);
- lock->held_by = me;
- }
-}
-
-static int
-debug_lock_lock(unsigned mode, void *lock_)
-{
- struct debug_lock *lock = lock_;
- int res = 0;
- if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
- EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
- else
- EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
- if (original_lock_fns_.lock)
- res = original_lock_fns_.lock(mode, lock->lock);
- if (!res) {
- evthread_debug_lock_mark_locked(mode, lock);
- }
- return res;
-}
-
-static void
-evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
-{
- EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
- if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
- EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
- else
- EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
- if (evthread_id_fn_) {
- unsigned long me;
- me = evthread_id_fn_();
- EVUTIL_ASSERT(lock->held_by == me);
- if (lock->count == 1)
- lock->held_by = 0;
- }
- --lock->count;
- EVUTIL_ASSERT(lock->count >= 0);
-}
-
-static int
-debug_lock_unlock(unsigned mode, void *lock_)
-{
- struct debug_lock *lock = lock_;
- int res = 0;
- evthread_debug_lock_mark_unlocked(mode, lock);
- if (original_lock_fns_.unlock)
- res = original_lock_fns_.unlock(mode, lock->lock);
- return res;
-}
-
-static int
-debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
-{
- int r;
- struct debug_lock *lock = lock_;
- EVUTIL_ASSERT(lock);
- EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
- EVLOCK_ASSERT_LOCKED(lock_);
- evthread_debug_lock_mark_unlocked(0, lock);
- r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
- evthread_debug_lock_mark_locked(0, lock);
- return r;
-}
-
-/* misspelled version for backward compatibility */
-void
-evthread_enable_lock_debuging(void)
-{
- evthread_enable_lock_debugging();
-}
-
-void
-evthread_enable_lock_debugging(void)
-{
- struct evthread_lock_callbacks cbs = {
- EVTHREAD_LOCK_API_VERSION,
- EVTHREAD_LOCKTYPE_RECURSIVE,
- debug_lock_alloc,
- debug_lock_free,
- debug_lock_lock,
- debug_lock_unlock
- };
- if (evthread_lock_debugging_enabled_)
- return;
- memcpy(&original_lock_fns_, &evthread_lock_fns_,
- sizeof(struct evthread_lock_callbacks));
- memcpy(&evthread_lock_fns_, &cbs,
- sizeof(struct evthread_lock_callbacks));
-
- memcpy(&original_cond_fns_, &evthread_cond_fns_,
- sizeof(struct evthread_condition_callbacks));
- evthread_cond_fns_.wait_condition = debug_cond_wait;
- evthread_lock_debugging_enabled_ = 1;
-
- /* XXX return value should get checked. */
- event_global_setup_locks_(0);
-}
-
-int
-evthread_is_debug_lock_held_(void *lock_)
-{
- struct debug_lock *lock = lock_;
- if (! lock->count)
- return 0;
- if (evthread_id_fn_) {
- unsigned long me = evthread_id_fn_();
- if (lock->held_by != me)
- return 0;
- }
- return 1;
-}
-
-void *
-evthread_debug_get_real_lock_(void *lock_)
-{
- struct debug_lock *lock = lock_;
- return lock->lock;
-}
-
-void *
-evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
-{
- /* there are four cases here:
- 1) we're turning on debugging; locking is not on.
- 2) we're turning on debugging; locking is on.
- 3) we're turning on locking; debugging is not on.
- 4) we're turning on locking; debugging is on. */
-
- if (!enable_locks && original_lock_fns_.alloc == NULL) {
- /* Case 1: allocate a debug lock. */
- EVUTIL_ASSERT(lock_ == NULL);
- return debug_lock_alloc(locktype);
- } else if (!enable_locks && original_lock_fns_.alloc != NULL) {
- /* Case 2: wrap the lock in a debug lock. */
- struct debug_lock *lock;
- EVUTIL_ASSERT(lock_ != NULL);
-
- if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
- /* We can't wrap it: We need a recursive lock */
- original_lock_fns_.free(lock_, locktype);
- return debug_lock_alloc(locktype);
- }
- lock = mm_malloc(sizeof(struct debug_lock));
- if (!lock) {
- original_lock_fns_.free(lock_, locktype);
- return NULL;
- }
- lock->lock = lock_;
- lock->locktype = locktype;
- lock->count = 0;
- lock->held_by = 0;
- return lock;
- } else if (enable_locks && ! evthread_lock_debugging_enabled_) {
- /* Case 3: allocate a regular lock */
- EVUTIL_ASSERT(lock_ == NULL);
- return evthread_lock_fns_.alloc(locktype);
- } else {
- /* Case 4: Fill in a debug lock with a real lock */
- struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype);
- EVUTIL_ASSERT(enable_locks &&
- evthread_lock_debugging_enabled_);
- EVUTIL_ASSERT(lock->locktype == locktype);
- if (!lock->lock) {
- lock->lock = original_lock_fns_.alloc(
- locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
- if (!lock->lock) {
- lock->count = -200;
- mm_free(lock);
- return NULL;
- }
- }
- return lock;
- }
-}
-
-
-#ifndef EVTHREAD_EXPOSE_STRUCTS
-unsigned long
-evthreadimpl_get_id_()
-{
- return evthread_id_fn_ ? evthread_id_fn_() : 1;
-}
-void *
-evthreadimpl_lock_alloc_(unsigned locktype)
-{
-#ifndef EVENT__DISABLE_DEBUG_MODE
- if (event_debug_mode_on_) {
- event_debug_created_threadable_ctx_ = 1;
- }
-#endif
-
- return evthread_lock_fns_.alloc ?
- evthread_lock_fns_.alloc(locktype) : NULL;
-}
-void
-evthreadimpl_lock_free_(void *lock, unsigned locktype)
-{
- if (evthread_lock_fns_.free)
- evthread_lock_fns_.free(lock, locktype);
-}
-int
-evthreadimpl_lock_lock_(unsigned mode, void *lock)
-{
- if (evthread_lock_fns_.lock)
- return evthread_lock_fns_.lock(mode, lock);
- else
- return 0;
-}
-int
-evthreadimpl_lock_unlock_(unsigned mode, void *lock)
-{
- if (evthread_lock_fns_.unlock)
- return evthread_lock_fns_.unlock(mode, lock);
- else
- return 0;
-}
-void *
-evthreadimpl_cond_alloc_(unsigned condtype)
-{
-#ifndef EVENT__DISABLE_DEBUG_MODE
- if (event_debug_mode_on_) {
- event_debug_created_threadable_ctx_ = 1;
- }
-#endif
-
- return evthread_cond_fns_.alloc_condition ?
- evthread_cond_fns_.alloc_condition(condtype) : NULL;
-}
-void
-evthreadimpl_cond_free_(void *cond)
-{
- if (evthread_cond_fns_.free_condition)
- evthread_cond_fns_.free_condition(cond);
-}
-int
-evthreadimpl_cond_signal_(void *cond, int broadcast)
-{
- if (evthread_cond_fns_.signal_condition)
- return evthread_cond_fns_.signal_condition(cond, broadcast);
- else
- return 0;
-}
-int
-evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
-{
- if (evthread_cond_fns_.wait_condition)
- return evthread_cond_fns_.wait_condition(cond, lock, tv);
- else
- return 0;
-}
-int
-evthreadimpl_is_lock_debugging_enabled_(void)
-{
- return evthread_lock_debugging_enabled_;
-}
-
-int
-evthreadimpl_locking_enabled_(void)
-{
- return evthread_lock_fns_.lock != NULL;
-}
-#endif
-
-#endif
diff --git a/libs/libevent/src/evthread_win32.c b/libs/libevent/src/evthread_win32.c
deleted file mode 100644
index 2ec80560a5..0000000000
--- a/libs/libevent/src/evthread_win32.c
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright 2009-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#ifndef _WIN32_WINNT
-/* Minimum required for InitializeCriticalSectionAndSpinCount */
-#define _WIN32_WINNT 0x0403
-#endif
-#include <winsock2.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#include <sys/locking.h>
-#endif
-
-struct event_base;
-#include "event2/thread.h"
-
-#include "mm-internal.h"
-#include "evthread-internal.h"
-#include "time-internal.h"
-
-#define SPIN_COUNT 2000
-
-static void *
-evthread_win32_lock_create(unsigned locktype)
-{
- CRITICAL_SECTION *lock = mm_malloc(sizeof(CRITICAL_SECTION));
- if (!lock)
- return NULL;
- if (InitializeCriticalSectionAndSpinCount(lock, SPIN_COUNT) == 0) {
- mm_free(lock);
- return NULL;
- }
- return lock;
-}
-
-static void
-evthread_win32_lock_free(void *lock_, unsigned locktype)
-{
- CRITICAL_SECTION *lock = lock_;
- DeleteCriticalSection(lock);
- mm_free(lock);
-}
-
-static int
-evthread_win32_lock(unsigned mode, void *lock_)
-{
- CRITICAL_SECTION *lock = lock_;
- if ((mode & EVTHREAD_TRY)) {
- return ! TryEnterCriticalSection(lock);
- } else {
- EnterCriticalSection(lock);
- return 0;
- }
-}
-
-static int
-evthread_win32_unlock(unsigned mode, void *lock_)
-{
- CRITICAL_SECTION *lock = lock_;
- LeaveCriticalSection(lock);
- return 0;
-}
-
-static unsigned long
-evthread_win32_get_id(void)
-{
- return (unsigned long) GetCurrentThreadId();
-}
-
-#ifdef WIN32_HAVE_CONDITION_VARIABLES
-static void WINAPI (*InitializeConditionVariable_fn)(PCONDITION_VARIABLE)
- = NULL;
-static BOOL WINAPI (*SleepConditionVariableCS_fn)(
- PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD) = NULL;
-static void WINAPI (*WakeAllConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
-static void WINAPI (*WakeConditionVariable_fn)(PCONDITION_VARIABLE) = NULL;
-
-static int
-evthread_win32_condvar_init(void)
-{
- HANDLE lib;
-
- lib = GetModuleHandle(TEXT("kernel32.dll"));
- if (lib == NULL)
- return 0;
-
-#define LOAD(name) \
- name##_fn = GetProcAddress(lib, #name)
- LOAD(InitializeConditionVariable);
- LOAD(SleepConditionVariableCS);
- LOAD(WakeAllConditionVariable);
- LOAD(WakeConditionVariable);
-
- return InitializeConditionVariable_fn && SleepConditionVariableCS_fn &&
- WakeAllConditionVariable_fn && WakeConditionVariable_fn;
-}
-
-/* XXXX Even if we can build this, we don't necessarily want to: the functions
- * in question didn't exist before Vista, so we'd better LoadProc them. */
-static void *
-evthread_win32_condvar_alloc(unsigned condflags)
-{
- CONDITION_VARIABLE *cond = mm_malloc(sizeof(CONDITION_VARIABLE));
- if (!cond)
- return NULL;
- InitializeConditionVariable_fn(cond);
- return cond;
-}
-
-static void
-evthread_win32_condvar_free(void *cond_)
-{
- CONDITION_VARIABLE *cond = cond_;
- /* There doesn't _seem_ to be a cleaup fn here... */
- mm_free(cond);
-}
-
-static int
-evthread_win32_condvar_signal(void *cond, int broadcast)
-{
- CONDITION_VARIABLE *cond = cond_;
- if (broadcast)
- WakeAllConditionVariable_fn(cond);
- else
- WakeConditionVariable_fn(cond);
- return 0;
-}
-
-static int
-evthread_win32_condvar_wait(void *cond_, void *lock_, const struct timeval *tv)
-{
- CONDITION_VARIABLE *cond = cond_;
- CRITICAL_SECTION *lock = lock_;
- DWORD ms, err;
- BOOL result;
-
- if (tv)
- ms = evutil_tv_to_msec_(tv);
- else
- ms = INFINITE;
- result = SleepConditionVariableCS_fn(cond, lock, ms);
- if (result) {
- if (GetLastError() == WAIT_TIMEOUT)
- return 1;
- else
- return -1;
- } else {
- return 0;
- }
-}
-#endif
-
-struct evthread_win32_cond {
- HANDLE event;
-
- CRITICAL_SECTION lock;
- int n_waiting;
- int n_to_wake;
- int generation;
-};
-
-static void *
-evthread_win32_cond_alloc(unsigned flags)
-{
- struct evthread_win32_cond *cond;
- if (!(cond = mm_malloc(sizeof(struct evthread_win32_cond))))
- return NULL;
- if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
- mm_free(cond);
- return NULL;
- }
- if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
- DeleteCriticalSection(&cond->lock);
- mm_free(cond);
- return NULL;
- }
- cond->n_waiting = cond->n_to_wake = cond->generation = 0;
- return cond;
-}
-
-static void
-evthread_win32_cond_free(void *cond_)
-{
- struct evthread_win32_cond *cond = cond_;
- DeleteCriticalSection(&cond->lock);
- CloseHandle(cond->event);
- mm_free(cond);
-}
-
-static int
-evthread_win32_cond_signal(void *cond_, int broadcast)
-{
- struct evthread_win32_cond *cond = cond_;
- EnterCriticalSection(&cond->lock);
- if (broadcast)
- cond->n_to_wake = cond->n_waiting;
- else
- ++cond->n_to_wake;
- cond->generation++;
- SetEvent(cond->event);
- LeaveCriticalSection(&cond->lock);
- return 0;
-}
-
-static int
-evthread_win32_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
-{
- struct evthread_win32_cond *cond = cond_;
- CRITICAL_SECTION *lock = lock_;
- int generation_at_start;
- int waiting = 1;
- int result = -1;
- DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
- if (tv)
- ms_orig = ms = evutil_tv_to_msec_(tv);
-
- EnterCriticalSection(&cond->lock);
- ++cond->n_waiting;
- generation_at_start = cond->generation;
- LeaveCriticalSection(&cond->lock);
-
- LeaveCriticalSection(lock);
-
- startTime = GetTickCount();
- do {
- DWORD res;
- res = WaitForSingleObject(cond->event, ms);
- EnterCriticalSection(&cond->lock);
- if (cond->n_to_wake &&
- cond->generation != generation_at_start) {
- --cond->n_to_wake;
- --cond->n_waiting;
- result = 0;
- waiting = 0;
- goto out;
- } else if (res != WAIT_OBJECT_0) {
- result = (res==WAIT_TIMEOUT) ? 1 : -1;
- --cond->n_waiting;
- waiting = 0;
- goto out;
- } else if (ms != INFINITE) {
- endTime = GetTickCount();
- if (startTime + ms_orig <= endTime) {
- result = 1; /* Timeout */
- --cond->n_waiting;
- waiting = 0;
- goto out;
- } else {
- ms = startTime + ms_orig - endTime;
- }
- }
- /* If we make it here, we are still waiting. */
- if (cond->n_to_wake == 0) {
- /* There is nobody else who should wake up; reset
- * the event. */
- ResetEvent(cond->event);
- }
- out:
- LeaveCriticalSection(&cond->lock);
- } while (waiting);
-
- EnterCriticalSection(lock);
-
- EnterCriticalSection(&cond->lock);
- if (!cond->n_waiting)
- ResetEvent(cond->event);
- LeaveCriticalSection(&cond->lock);
-
- return result;
-}
-
-int
-evthread_use_windows_threads(void)
-{
- struct evthread_lock_callbacks cbs = {
- EVTHREAD_LOCK_API_VERSION,
- EVTHREAD_LOCKTYPE_RECURSIVE,
- evthread_win32_lock_create,
- evthread_win32_lock_free,
- evthread_win32_lock,
- evthread_win32_unlock
- };
-
-
- struct evthread_condition_callbacks cond_cbs = {
- EVTHREAD_CONDITION_API_VERSION,
- evthread_win32_cond_alloc,
- evthread_win32_cond_free,
- evthread_win32_cond_signal,
- evthread_win32_cond_wait
- };
-#ifdef WIN32_HAVE_CONDITION_VARIABLES
- struct evthread_condition_callbacks condvar_cbs = {
- EVTHREAD_CONDITION_API_VERSION,
- evthread_win32_condvar_alloc,
- evthread_win32_condvar_free,
- evthread_win32_condvar_signal,
- evthread_win32_condvar_wait
- };
-#endif
-
- evthread_set_lock_callbacks(&cbs);
- evthread_set_id_callback(evthread_win32_get_id);
-#ifdef WIN32_HAVE_CONDITION_VARIABLES
- if (evthread_win32_condvar_init()) {
- evthread_set_condition_callbacks(&condvar_cbs);
- return 0;
- }
-#endif
- evthread_set_condition_callbacks(&cond_cbs);
-
- return 0;
-}
-
diff --git a/libs/libevent/src/evutil.c b/libs/libevent/src/evutil.c
deleted file mode 100644
index 0ea9bc7521..0000000000
--- a/libs/libevent/src/evutil.c
+++ /dev/null
@@ -1,2666 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#include <io.h>
-#include <process.h>
-#undef _WIN32_WINNT
-/* For structs needed by GetAdaptersAddresses */
-#define _WIN32_WINNT 0x0501
-#include <iphlpapi.h>
-#endif
-
-#include <sys/types.h>
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef EVENT__HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef EVENT__HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef EVENT__HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef EVENT__HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-#ifdef EVENT__HAVE_NETINET_TCP_H
-#include <netinet/tcp.h>
-#endif
-#ifdef EVENT__HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#include <time.h>
-#include <sys/stat.h>
-#ifdef EVENT__HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#endif
-
-#include "event2/util.h"
-#include "util-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-#include "evthread-internal.h"
-
-#include "strlcpy-internal.h"
-#include "ipv6-internal.h"
-
-#ifdef _WIN32
-#define HT_NO_CACHE_HASH_VALUES
-#include "ht-internal.h"
-#define open _open
-#define read _read
-#define close _close
-#ifndef fstat
-#define fstat _fstati64
-#endif
-#ifndef stat
-#define stat _stati64
-#endif
-#define mode_t int
-#endif
-
-int
-evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode)
-{
- int fd;
-
-#ifdef O_CLOEXEC
- fd = open(pathname, flags|O_CLOEXEC, (mode_t)mode);
- if (fd >= 0 || errno == EINVAL)
- return fd;
- /* If we got an EINVAL, fall through and try without O_CLOEXEC */
-#endif
- fd = open(pathname, flags, (mode_t)mode);
- if (fd < 0)
- return -1;
-
-#if defined(FD_CLOEXEC)
- if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
- close(fd);
- return -1;
- }
-#endif
-
- return fd;
-}
-
-/**
- Read the contents of 'filename' into a newly allocated NUL-terminated
- string. Set *content_out to hold this string, and *len_out to hold its
- length (not including the appended NUL). If 'is_binary', open the file in
- binary mode.
-
- Returns 0 on success, -1 if the open fails, and -2 for all other failures.
-
- Used internally only; may go away in a future version.
- */
-int
-evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
- int is_binary)
-{
- int fd, r;
- struct stat st;
- char *mem;
- size_t read_so_far=0;
- int mode = O_RDONLY;
-
- EVUTIL_ASSERT(content_out);
- EVUTIL_ASSERT(len_out);
- *content_out = NULL;
- *len_out = 0;
-
-#ifdef O_BINARY
- if (is_binary)
- mode |= O_BINARY;
-#endif
-
- fd = evutil_open_closeonexec_(filename, mode, 0);
- if (fd < 0)
- return -1;
- if (fstat(fd, &st) || st.st_size < 0 ||
- st.st_size > EV_SSIZE_MAX-1 ) {
- close(fd);
- return -2;
- }
- mem = mm_malloc((size_t)st.st_size + 1);
- if (!mem) {
- close(fd);
- return -2;
- }
- read_so_far = 0;
-#ifdef _WIN32
-#define N_TO_READ(x) ((x) > INT_MAX) ? INT_MAX : ((int)(x))
-#else
-#define N_TO_READ(x) (x)
-#endif
- while ((r = read(fd, mem+read_so_far, N_TO_READ(st.st_size - read_so_far))) > 0) {
- read_so_far += r;
- if (read_so_far >= (size_t)st.st_size)
- break;
- EVUTIL_ASSERT(read_so_far < (size_t)st.st_size);
- }
- close(fd);
- if (r < 0) {
- mm_free(mem);
- return -2;
- }
- mem[read_so_far] = 0;
-
- *len_out = read_so_far;
- *content_out = mem;
- return 0;
-}
-
-int
-evutil_socketpair(int family, int type, int protocol, evutil_socket_t fd[2])
-{
-#ifndef _WIN32
- return socketpair(family, type, protocol, fd);
-#else
- return evutil_ersatz_socketpair_(family, type, protocol, fd);
-#endif
-}
-
-int
-evutil_ersatz_socketpair_(int family, int type, int protocol,
- evutil_socket_t fd[2])
-{
- /* 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.
- */
-#ifdef _WIN32
-#define ERR(e) WSA##e
-#else
-#define ERR(e) e
-#endif
- evutil_socket_t listener = -1;
- evutil_socket_t connector = -1;
- evutil_socket_t acceptor = -1;
- struct sockaddr_in listen_addr;
- struct sockaddr_in connect_addr;
- ev_socklen_t size;
- int saved_errno = -1;
- int family_test;
-
- family_test = family != AF_INET;
-#ifdef AF_UNIX
- family_test = family_test && (family != AF_UNIX);
-#endif
- if (protocol || family_test) {
- EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT));
- return -1;
- }
-
- if (!fd) {
- EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL));
- return -1;
- }
-
- listener = 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 = socket(AF_INET, type, 0);
- if (connector < 0)
- goto tidy_up_and_fail;
-
- memset(&connect_addr, 0, sizeof(connect_addr));
-
- /* 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 = 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;
- /* 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;
- evutil_closesocket(listener);
- fd[0] = connector;
- fd[1] = acceptor;
-
- return 0;
-
- abort_tidy_up_and_fail:
- saved_errno = ERR(ECONNABORTED);
- tidy_up_and_fail:
- if (saved_errno < 0)
- saved_errno = EVUTIL_SOCKET_ERROR();
- 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;
-#undef ERR
-}
-
-int
-evutil_make_socket_nonblocking(evutil_socket_t fd)
-{
-#ifdef _WIN32
- {
- unsigned long nonblocking = 1;
- if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
- event_sock_warn(fd, "fcntl(%d, F_GETFL)", (int)fd);
- return -1;
- }
- }
-#else
- {
- int flags;
- if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
- event_warn("fcntl(%d, F_GETFL)", fd);
- return -1;
- }
- if (!(flags & O_NONBLOCK)) {
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
- event_warn("fcntl(%d, F_SETFL)", fd);
- return -1;
- }
- }
- }
-#endif
- return 0;
-}
-
-/* Faster version of evutil_make_socket_nonblocking for internal use.
- *
- * Requires that no F_SETFL flags were previously set on the fd.
- */
-static int
-evutil_fast_socket_nonblocking(evutil_socket_t fd)
-{
-#ifdef _WIN32
- return evutil_make_socket_nonblocking(fd);
-#else
- if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
- event_warn("fcntl(%d, F_SETFL)", fd);
- return -1;
- }
- return 0;
-#endif
-}
-
-int
-evutil_make_listen_socket_reuseable(evutil_socket_t sock)
-{
-#if defined(SO_REUSEADDR) && !defined(_WIN32)
- int one = 1;
- /* REUSEADDR on Unix means, "don't hang on to this address after the
- * listener is closed." On Windows, though, it means "don't keep other
- * processes from binding to this address while we're using it. */
- return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one,
- (ev_socklen_t)sizeof(one));
-#else
- return 0;
-#endif
-}
-
-int
-evutil_make_listen_socket_reuseable_port(evutil_socket_t sock)
-{
-#if defined __linux__ && defined(SO_REUSEPORT)
- int one = 1;
- /* REUSEPORT on Linux 3.9+ means, "Multiple servers (processes or
- * threads) can bind to the same port if they each set the option. */
- return setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void*) &one,
- (ev_socklen_t)sizeof(one));
-#else
- return 0;
-#endif
-}
-
-int
-evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock)
-{
-#if defined(EVENT__HAVE_NETINET_TCP_H) && defined(TCP_DEFER_ACCEPT)
- int one = 1;
-
- /* TCP_DEFER_ACCEPT tells the kernel to call defer accept() only after data
- * has arrived and ready to read */
- return setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &one,
- (ev_socklen_t)sizeof(one));
-#endif
- return 0;
-}
-
-int
-evutil_make_socket_closeonexec(evutil_socket_t fd)
-{
-#if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
- int flags;
- if ((flags = fcntl(fd, F_GETFD, NULL)) < 0) {
- event_warn("fcntl(%d, F_GETFD)", fd);
- return -1;
- }
- if (!(flags & FD_CLOEXEC)) {
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
- event_warn("fcntl(%d, F_SETFD)", fd);
- return -1;
- }
- }
-#endif
- return 0;
-}
-
-/* Faster version of evutil_make_socket_closeonexec for internal use.
- *
- * Requires that no F_SETFD flags were previously set on the fd.
- */
-static int
-evutil_fast_socket_closeonexec(evutil_socket_t fd)
-{
-#if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
- if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
- event_warn("fcntl(%d, F_SETFD)", fd);
- return -1;
- }
-#endif
- return 0;
-}
-
-int
-evutil_closesocket(evutil_socket_t sock)
-{
-#ifndef _WIN32
- return close(sock);
-#else
- return closesocket(sock);
-#endif
-}
-
-ev_int64_t
-evutil_strtoll(const char *s, char **endptr, int base)
-{
-#ifdef EVENT__HAVE_STRTOLL
- return (ev_int64_t)strtoll(s, endptr, base);
-#elif EVENT__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;
- if (*s == '-')
- ++s;
- while (isdigit(*s))
- ++s;
- if (endptr)
- *endptr = (char*) s;
- return r;
-#elif defined(_WIN32)
- return (ev_int64_t) _strtoi64(s, endptr, base);
-#elif defined(EVENT__SIZEOF_LONG_LONG) && EVENT__SIZEOF_LONG_LONG == 8
- long long r;
- int n;
- if (base != 10 && base != 16)
- return 0;
- if (base == 10) {
- n = sscanf(s, "%lld", &r);
- } else {
- unsigned long long ru=0;
- n = sscanf(s, "%llx", &ru);
- if (ru > EV_INT64_MAX)
- return 0;
- r = (long long) ru;
- }
- if (n != 1)
- return 0;
- while (EVUTIL_ISSPACE_(*s))
- ++s;
- if (*s == '-')
- ++s;
- if (base == 10) {
- while (EVUTIL_ISDIGIT_(*s))
- ++s;
- } else {
- while (EVUTIL_ISXDIGIT_(*s))
- ++s;
- }
- if (endptr)
- *endptr = (char*) s;
- return r;
-#else
-#error "I don't know how to parse 64-bit integers."
-#endif
-}
-
-#ifdef _WIN32
-int
-evutil_socket_geterror(evutil_socket_t 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;
-}
-#endif
-
-/* XXX we should use an enum here. */
-/* 2 for connection refused, 1 for connected, 0 for not yet, -1 for error. */
-int
-evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen)
-{
- int made_fd = 0;
-
- if (*fd_ptr < 0) {
- if ((*fd_ptr = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
- goto err;
- made_fd = 1;
- if (evutil_make_socket_nonblocking(*fd_ptr) < 0) {
- goto err;
- }
- }
-
- if (connect(*fd_ptr, sa, socklen) < 0) {
- int e = evutil_socket_geterror(*fd_ptr);
- if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
- return 0;
- if (EVUTIL_ERR_CONNECT_REFUSED(e))
- return 2;
- goto err;
- } else {
- return 1;
- }
-
-err:
- if (made_fd) {
- evutil_closesocket(*fd_ptr);
- *fd_ptr = -1;
- }
- return -1;
-}
-
-/* Check whether a socket on which we called connect() is done
- connecting. Return 1 for connected, 0 for not yet, -1 for error. In the
- error case, set the current socket errno to the error that happened during
- the connect operation. */
-int
-evutil_socket_finished_connecting_(evutil_socket_t fd)
-{
- int e;
- ev_socklen_t elen = sizeof(e);
-
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&e, &elen) < 0)
- return -1;
-
- if (e) {
- if (EVUTIL_ERR_CONNECT_RETRIABLE(e))
- return 0;
- EVUTIL_SET_SOCKET_ERROR(e);
- return -1;
- }
-
- return 1;
-}
-
-#if (EVUTIL_AI_PASSIVE|EVUTIL_AI_CANONNAME|EVUTIL_AI_NUMERICHOST| \
- EVUTIL_AI_NUMERICSERV|EVUTIL_AI_V4MAPPED|EVUTIL_AI_ALL| \
- EVUTIL_AI_ADDRCONFIG) != \
- (EVUTIL_AI_PASSIVE^EVUTIL_AI_CANONNAME^EVUTIL_AI_NUMERICHOST^ \
- EVUTIL_AI_NUMERICSERV^EVUTIL_AI_V4MAPPED^EVUTIL_AI_ALL^ \
- EVUTIL_AI_ADDRCONFIG)
-#error "Some of our EVUTIL_AI_* flags seem to overlap with system AI_* flags"
-#endif
-
-/* We sometimes need to know whether we have an ipv4 address and whether we
- have an ipv6 address. If 'have_checked_interfaces', then we've already done
- the test. If 'had_ipv4_address', then it turns out we had an ipv4 address.
- If 'had_ipv6_address', then it turns out we had an ipv6 address. These are
- set by evutil_check_interfaces. */
-static int have_checked_interfaces, had_ipv4_address, had_ipv6_address;
-
-/* Macro: True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8
- */
-#define EVUTIL_V4ADDR_IS_LOCALHOST(addr) (((addr)>>24) == 127)
-
-/* Macro: True iff the IPv4 address 'addr', in host order, is a class D
- * (multiclass) address.
- */
-#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0)
-
-static void
-evutil_found_ifaddr(const struct sockaddr *sa)
-{
- const char ZEROES[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00";
-
- if (sa->sa_family == AF_INET) {
- const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
- ev_uint32_t addr = ntohl(sin->sin_addr.s_addr);
- if (addr == 0 ||
- EVUTIL_V4ADDR_IS_LOCALHOST(addr) ||
- EVUTIL_V4ADDR_IS_CLASSD(addr)) {
- /* Not actually a usable external address. */
- } else {
- event_debug(("Detected an IPv4 interface"));
- had_ipv4_address = 1;
- }
- } else if (sa->sa_family == AF_INET6) {
- const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
- const unsigned char *addr =
- (unsigned char*)sin6->sin6_addr.s6_addr;
- if (!memcmp(addr, ZEROES, 8) ||
- ((addr[0] & 0xfe) == 0xfc) ||
- (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
- (addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
- (addr[0] == 0xff)) {
- /* This is a reserved, ipv4compat, ipv4map, loopback,
- * link-local, multicast, or unspecified address. */
- } else {
- event_debug(("Detected an IPv6 interface"));
- had_ipv6_address = 1;
- }
- }
-}
-
-#ifdef _WIN32
-typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
- ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
-#endif
-
-static int
-evutil_check_ifaddrs(void)
-{
-#if defined(EVENT__HAVE_GETIFADDRS)
- /* Most free Unixy systems provide getifaddrs, which gives us a linked list
- * of struct ifaddrs. */
- struct ifaddrs *ifa = NULL;
- const struct ifaddrs *i;
- if (getifaddrs(&ifa) < 0) {
- event_warn("Unable to call getifaddrs()");
- return -1;
- }
-
- for (i = ifa; i; i = i->ifa_next) {
- if (!i->ifa_addr)
- continue;
- evutil_found_ifaddr(i->ifa_addr);
- }
-
- freeifaddrs(ifa);
- return 0;
-#elif defined(_WIN32)
- /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
- "GetAdaptersInfo", but that's deprecated; let's just try
- GetAdaptersAddresses and fall back to connect+getsockname.
- */
- HMODULE lib = evutil_load_windows_system_library_(TEXT("ihplapi.dll"));
- GetAdaptersAddresses_fn_t fn;
- ULONG size, res;
- IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
- int result = -1;
-
-#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
- GAA_FLAG_SKIP_MULTICAST | \
- GAA_FLAG_SKIP_DNS_SERVER)
-
- if (!lib)
- goto done;
-
- if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses")))
- goto done;
-
- /* Guess how much space we need. */
- size = 15*1024;
- addresses = mm_malloc(size);
- if (!addresses)
- goto done;
- res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
- if (res == ERROR_BUFFER_OVERFLOW) {
- /* we didn't guess that we needed enough space; try again */
- mm_free(addresses);
- addresses = mm_malloc(size);
- if (!addresses)
- goto done;
- res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
- }
- if (res != NO_ERROR)
- goto done;
-
- for (address = addresses; address; address = address->Next) {
- IP_ADAPTER_UNICAST_ADDRESS *a;
- for (a = address->FirstUnicastAddress; a; a = a->Next) {
- /* Yes, it's a linked list inside a linked list */
- struct sockaddr *sa = a->Address.lpSockaddr;
- evutil_found_ifaddr(sa);
- }
- }
-
- result = 0;
-done:
- if (lib)
- FreeLibrary(lib);
- if (addresses)
- mm_free(addresses);
- return result;
-#else
- return -1;
-#endif
-}
-
-/* Test whether we have an ipv4 interface and an ipv6 interface. Return 0 if
- * the test seemed successful. */
-static int
-evutil_check_interfaces(int force_recheck)
-{
- evutil_socket_t fd = -1;
- struct sockaddr_in sin, sin_out;
- struct sockaddr_in6 sin6, sin6_out;
- ev_socklen_t sin_out_len = sizeof(sin_out);
- ev_socklen_t sin6_out_len = sizeof(sin6_out);
- int r;
- if (have_checked_interfaces && !force_recheck)
- return 0;
-
- if (evutil_check_ifaddrs() == 0) {
- /* Use a nice sane interface, if this system has one. */
- return 0;
- }
-
- /* Ugh. There was no nice sane interface. So to check whether we have
- * an interface open for a given protocol, will try to make a UDP
- * 'connection' to a remote host on the internet. We don't actually
- * use it, so the address doesn't matter, but we want to pick one that
- * keep us from using a host- or link-local interface. */
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(53);
- r = evutil_inet_pton(AF_INET, "18.244.0.188", &sin.sin_addr);
- EVUTIL_ASSERT(r);
-
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(53);
- r = evutil_inet_pton(AF_INET6, "2001:4860:b002::68", &sin6.sin6_addr);
- EVUTIL_ASSERT(r);
-
- memset(&sin_out, 0, sizeof(sin_out));
- memset(&sin6_out, 0, sizeof(sin6_out));
-
- /* XXX some errnos mean 'no address'; some mean 'not enough sockets'. */
- if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
- connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
- getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) {
- /* We might have an IPv4 interface. */
- evutil_found_ifaddr((struct sockaddr*) &sin_out);
- }
- if (fd >= 0)
- evutil_closesocket(fd);
-
- if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) >= 0 &&
- connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
- getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) {
- /* We might have an IPv6 interface. */
- evutil_found_ifaddr((struct sockaddr*) &sin6_out);
- }
-
- if (fd >= 0)
- evutil_closesocket(fd);
-
- return 0;
-}
-
-/* Internal addrinfo flag. This one is set when we allocate the addrinfo from
- * inside libevent. Otherwise, the built-in getaddrinfo() function allocated
- * it, and we should trust what they said.
- **/
-#define EVUTIL_AI_LIBEVENT_ALLOCATED 0x80000000
-
-/* Helper: construct a new addrinfo containing the socket address in
- * 'sa', which must be a sockaddr_in or a sockaddr_in6. Take the
- * socktype and protocol info from hints. If they weren't set, then
- * allocate both a TCP and a UDP addrinfo.
- */
-struct evutil_addrinfo *
-evutil_new_addrinfo_(struct sockaddr *sa, ev_socklen_t socklen,
- const struct evutil_addrinfo *hints)
-{
- struct evutil_addrinfo *res;
- EVUTIL_ASSERT(hints);
-
- if (hints->ai_socktype == 0 && hints->ai_protocol == 0) {
- /* Indecisive user! Give them a UDP and a TCP. */
- struct evutil_addrinfo *r1, *r2;
- struct evutil_addrinfo tmp;
- memcpy(&tmp, hints, sizeof(tmp));
- tmp.ai_socktype = SOCK_STREAM; tmp.ai_protocol = IPPROTO_TCP;
- r1 = evutil_new_addrinfo_(sa, socklen, &tmp);
- if (!r1)
- return NULL;
- tmp.ai_socktype = SOCK_DGRAM; tmp.ai_protocol = IPPROTO_UDP;
- r2 = evutil_new_addrinfo_(sa, socklen, &tmp);
- if (!r2) {
- evutil_freeaddrinfo(r1);
- return NULL;
- }
- r1->ai_next = r2;
- return r1;
- }
-
- /* We're going to allocate extra space to hold the sockaddr. */
- res = mm_calloc(1,sizeof(struct evutil_addrinfo)+socklen);
- if (!res)
- return NULL;
- res->ai_addr = (struct sockaddr*)
- (((char*)res) + sizeof(struct evutil_addrinfo));
- memcpy(res->ai_addr, sa, socklen);
- res->ai_addrlen = socklen;
- res->ai_family = sa->sa_family; /* Same or not? XXX */
- res->ai_flags = EVUTIL_AI_LIBEVENT_ALLOCATED;
- res->ai_socktype = hints->ai_socktype;
- res->ai_protocol = hints->ai_protocol;
-
- return res;
-}
-
-/* Append the addrinfo 'append' to the end of 'first', and return the start of
- * the list. Either element can be NULL, in which case we return the element
- * that is not NULL. */
-struct evutil_addrinfo *
-evutil_addrinfo_append_(struct evutil_addrinfo *first,
- struct evutil_addrinfo *append)
-{
- struct evutil_addrinfo *ai = first;
- if (!ai)
- return append;
- while (ai->ai_next)
- ai = ai->ai_next;
- ai->ai_next = append;
-
- return first;
-}
-
-static int
-parse_numeric_servname(const char *servname)
-{
- int n;
- char *endptr=NULL;
- n = (int) strtol(servname, &endptr, 10);
- if (n>=0 && n <= 65535 && servname[0] && endptr && !endptr[0])
- return n;
- else
- return -1;
-}
-
-/** Parse a service name in 'servname', which can be a decimal port.
- * Return the port number, or -1 on error.
- */
-static int
-evutil_parse_servname(const char *servname, const char *protocol,
- const struct evutil_addrinfo *hints)
-{
- int n = parse_numeric_servname(servname);
- if (n>=0)
- return n;
-#if defined(EVENT__HAVE_GETSERVBYNAME) || defined(_WIN32)
- if (!(hints->ai_flags & EVUTIL_AI_NUMERICSERV)) {
- struct servent *ent = getservbyname(servname, protocol);
- if (ent) {
- return ntohs(ent->s_port);
- }
- }
-#endif
- return -1;
-}
-
-/* Return a string corresponding to a protocol number that we can pass to
- * getservyname. */
-static const char *
-evutil_unparse_protoname(int proto)
-{
- switch (proto) {
- case 0:
- return NULL;
- case IPPROTO_TCP:
- return "tcp";
- case IPPROTO_UDP:
- return "udp";
-#ifdef IPPROTO_SCTP
- case IPPROTO_SCTP:
- return "sctp";
-#endif
- default:
-#ifdef EVENT__HAVE_GETPROTOBYNUMBER
- {
- struct protoent *ent = getprotobynumber(proto);
- if (ent)
- return ent->p_name;
- }
-#endif
- return NULL;
- }
-}
-
-static void
-evutil_getaddrinfo_infer_protocols(struct evutil_addrinfo *hints)
-{
- /* If we can guess the protocol from the socktype, do so. */
- if (!hints->ai_protocol && hints->ai_socktype) {
- if (hints->ai_socktype == SOCK_DGRAM)
- hints->ai_protocol = IPPROTO_UDP;
- else if (hints->ai_socktype == SOCK_STREAM)
- hints->ai_protocol = IPPROTO_TCP;
- }
-
- /* Set the socktype if it isn't set. */
- if (!hints->ai_socktype && hints->ai_protocol) {
- if (hints->ai_protocol == IPPROTO_UDP)
- hints->ai_socktype = SOCK_DGRAM;
- else if (hints->ai_protocol == IPPROTO_TCP)
- hints->ai_socktype = SOCK_STREAM;
-#ifdef IPPROTO_SCTP
- else if (hints->ai_protocol == IPPROTO_SCTP)
- hints->ai_socktype = SOCK_STREAM;
-#endif
- }
-}
-
-#if AF_UNSPEC != PF_UNSPEC
-#error "I cannot build on a system where AF_UNSPEC != PF_UNSPEC"
-#endif
-
-/** Implements the part of looking up hosts by name that's common to both
- * the blocking and nonblocking resolver:
- * - Adjust 'hints' to have a reasonable socktype and protocol.
- * - Look up the port based on 'servname', and store it in *portnum,
- * - Handle the nodename==NULL case
- * - Handle some invalid arguments cases.
- * - Handle the cases where nodename is an IPv4 or IPv6 address.
- *
- * If we need the resolver to look up the hostname, we return
- * EVUTIL_EAI_NEED_RESOLVE. Otherwise, we can completely implement
- * getaddrinfo: we return 0 or an appropriate EVUTIL_EAI_* error, and
- * set *res as getaddrinfo would.
- */
-int
-evutil_getaddrinfo_common_(const char *nodename, const char *servname,
- struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum)
-{
- int port = 0;
- const char *pname;
-
- if (nodename == NULL && servname == NULL)
- return EVUTIL_EAI_NONAME;
-
- /* We only understand 3 families */
- if (hints->ai_family != PF_UNSPEC && hints->ai_family != PF_INET &&
- hints->ai_family != PF_INET6)
- return EVUTIL_EAI_FAMILY;
-
- evutil_getaddrinfo_infer_protocols(hints);
-
- /* Look up the port number and protocol, if possible. */
- pname = evutil_unparse_protoname(hints->ai_protocol);
- if (servname) {
- /* XXXX We could look at the protocol we got back from
- * getservbyname, but it doesn't seem too useful. */
- port = evutil_parse_servname(servname, pname, hints);
- if (port < 0) {
- return EVUTIL_EAI_NONAME;
- }
- }
-
- /* If we have no node name, then we're supposed to bind to 'any' and
- * connect to localhost. */
- if (nodename == NULL) {
- struct evutil_addrinfo *res4=NULL, *res6=NULL;
- if (hints->ai_family != PF_INET) { /* INET6 or UNSPEC. */
- struct sockaddr_in6 sin6;
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(port);
- if (hints->ai_flags & EVUTIL_AI_PASSIVE) {
- /* Bind to :: */
- } else {
- /* connect to ::1 */
- sin6.sin6_addr.s6_addr[15] = 1;
- }
- res6 = evutil_new_addrinfo_((struct sockaddr*)&sin6,
- sizeof(sin6), hints);
- if (!res6)
- return EVUTIL_EAI_MEMORY;
- }
-
- if (hints->ai_family != PF_INET6) { /* INET or UNSPEC */
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- if (hints->ai_flags & EVUTIL_AI_PASSIVE) {
- /* Bind to 0.0.0.0 */
- } else {
- /* connect to 127.0.0.1 */
- sin.sin_addr.s_addr = htonl(0x7f000001);
- }
- res4 = evutil_new_addrinfo_((struct sockaddr*)&sin,
- sizeof(sin), hints);
- if (!res4) {
- if (res6)
- evutil_freeaddrinfo(res6);
- return EVUTIL_EAI_MEMORY;
- }
- }
- *res = evutil_addrinfo_append_(res4, res6);
- return 0;
- }
-
- /* If we can, we should try to parse the hostname without resolving
- * it. */
- /* Try ipv6. */
- if (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC) {
- struct sockaddr_in6 sin6;
- memset(&sin6, 0, sizeof(sin6));
- if (1==evutil_inet_pton(AF_INET6, nodename, &sin6.sin6_addr)) {
- /* Got an ipv6 address. */
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(port);
- *res = evutil_new_addrinfo_((struct sockaddr*)&sin6,
- sizeof(sin6), hints);
- if (!*res)
- return EVUTIL_EAI_MEMORY;
- return 0;
- }
- }
-
- /* Try ipv4. */
- if (hints->ai_family == PF_INET || hints->ai_family == PF_UNSPEC) {
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof(sin));
- if (1==evutil_inet_pton(AF_INET, nodename, &sin.sin_addr)) {
- /* Got an ipv6 address. */
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- *res = evutil_new_addrinfo_((struct sockaddr*)&sin,
- sizeof(sin), hints);
- if (!*res)
- return EVUTIL_EAI_MEMORY;
- return 0;
- }
- }
-
-
- /* If we have reached this point, we definitely need to do a DNS
- * lookup. */
- if ((hints->ai_flags & EVUTIL_AI_NUMERICHOST)) {
- /* If we're not allowed to do one, then say so. */
- return EVUTIL_EAI_NONAME;
- }
- *portnum = port;
- return EVUTIL_EAI_NEED_RESOLVE;
-}
-
-#ifdef EVENT__HAVE_GETADDRINFO
-#define USE_NATIVE_GETADDRINFO
-#endif
-
-#ifdef USE_NATIVE_GETADDRINFO
-/* A mask of all the flags that we declare, so we can clear them before calling
- * the native getaddrinfo */
-static const unsigned int ALL_NONNATIVE_AI_FLAGS =
-#ifndef AI_PASSIVE
- EVUTIL_AI_PASSIVE |
-#endif
-#ifndef AI_CANONNAME
- EVUTIL_AI_CANONNAME |
-#endif
-#ifndef AI_NUMERICHOST
- EVUTIL_AI_NUMERICHOST |
-#endif
-#ifndef AI_NUMERICSERV
- EVUTIL_AI_NUMERICSERV |
-#endif
-#ifndef AI_ADDRCONFIG
- EVUTIL_AI_ADDRCONFIG |
-#endif
-#ifndef AI_ALL
- EVUTIL_AI_ALL |
-#endif
-#ifndef AI_V4MAPPED
- EVUTIL_AI_V4MAPPED |
-#endif
- EVUTIL_AI_LIBEVENT_ALLOCATED;
-
-static const unsigned int ALL_NATIVE_AI_FLAGS =
-#ifdef AI_PASSIVE
- AI_PASSIVE |
-#endif
-#ifdef AI_CANONNAME
- AI_CANONNAME |
-#endif
-#ifdef AI_NUMERICHOST
- AI_NUMERICHOST |
-#endif
-#ifdef AI_NUMERICSERV
- AI_NUMERICSERV |
-#endif
-#ifdef AI_ADDRCONFIG
- AI_ADDRCONFIG |
-#endif
-#ifdef AI_ALL
- AI_ALL |
-#endif
-#ifdef AI_V4MAPPED
- AI_V4MAPPED |
-#endif
- 0;
-#endif
-
-#ifndef USE_NATIVE_GETADDRINFO
-/* Helper for systems with no getaddrinfo(): make one or more addrinfos out of
- * a struct hostent.
- */
-static struct evutil_addrinfo *
-addrinfo_from_hostent(const struct hostent *ent,
- int port, const struct evutil_addrinfo *hints)
-{
- int i;
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- struct sockaddr *sa;
- int socklen;
- struct evutil_addrinfo *res=NULL, *ai;
- void *addrp;
-
- if (ent->h_addrtype == PF_INET) {
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- sa = (struct sockaddr *)&sin;
- socklen = sizeof(struct sockaddr_in);
- addrp = &sin.sin_addr;
- if (ent->h_length != sizeof(sin.sin_addr)) {
- event_warnx("Weird h_length from gethostbyname");
- return NULL;
- }
- } else if (ent->h_addrtype == PF_INET6) {
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(port);
- sa = (struct sockaddr *)&sin6;
- socklen = sizeof(struct sockaddr_in6);
- addrp = &sin6.sin6_addr;
- if (ent->h_length != sizeof(sin6.sin6_addr)) {
- event_warnx("Weird h_length from gethostbyname");
- return NULL;
- }
- } else
- return NULL;
-
- for (i = 0; ent->h_addr_list[i]; ++i) {
- memcpy(addrp, ent->h_addr_list[i], ent->h_length);
- ai = evutil_new_addrinfo_(sa, socklen, hints);
- if (!ai) {
- evutil_freeaddrinfo(res);
- return NULL;
- }
- res = evutil_addrinfo_append_(res, ai);
- }
-
- if (res && ((hints->ai_flags & EVUTIL_AI_CANONNAME) && ent->h_name)) {
- res->ai_canonname = mm_strdup(ent->h_name);
- if (res->ai_canonname == NULL) {
- evutil_freeaddrinfo(res);
- return NULL;
- }
- }
-
- return res;
-}
-#endif
-
-/* If the EVUTIL_AI_ADDRCONFIG flag is set on hints->ai_flags, and
- * hints->ai_family is PF_UNSPEC, then revise the value of hints->ai_family so
- * that we'll only get addresses we could maybe connect to.
- */
-void
-evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints)
-{
- if (!(hints->ai_flags & EVUTIL_AI_ADDRCONFIG))
- return;
- if (hints->ai_family != PF_UNSPEC)
- return;
- if (!have_checked_interfaces)
- evutil_check_interfaces(0);
- if (had_ipv4_address && !had_ipv6_address) {
- hints->ai_family = PF_INET;
- } else if (!had_ipv4_address && had_ipv6_address) {
- hints->ai_family = PF_INET6;
- }
-}
-
-#ifdef USE_NATIVE_GETADDRINFO
-static int need_numeric_port_hack_=0;
-static int need_socktype_protocol_hack_=0;
-static int tested_for_getaddrinfo_hacks=0;
-
-/* Some older BSDs (like OpenBSD up to 4.6) used to believe that
- giving a numeric port without giving an ai_socktype was verboten.
- We test for this so we can apply an appropriate workaround. If it
- turns out that the bug is present, then:
-
- - If nodename==NULL and servname is numeric, we build an answer
- ourselves using evutil_getaddrinfo_common_().
-
- - If nodename!=NULL and servname is numeric, then we set
- servname=NULL when calling getaddrinfo, and post-process the
- result to set the ports on it.
-
- We test for this bug at runtime, since otherwise we can't have the
- same binary run on multiple BSD versions.
-
- - Some versions of Solaris believe that it's nice to leave to protocol
- field set to 0. We test for this so we can apply an appropriate
- workaround.
-*/
-static void
-test_for_getaddrinfo_hacks(void)
-{
- int r, r2;
- struct evutil_addrinfo *ai=NULL, *ai2=NULL;
- struct evutil_addrinfo hints;
-
- memset(&hints,0,sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_flags =
-#ifdef AI_NUMERICHOST
- AI_NUMERICHOST |
-#endif
-#ifdef AI_NUMERICSERV
- AI_NUMERICSERV |
-#endif
- 0;
- r = getaddrinfo("1.2.3.4", "80", &hints, &ai);
- hints.ai_socktype = SOCK_STREAM;
- r2 = getaddrinfo("1.2.3.4", "80", &hints, &ai2);
- if (r2 == 0 && r != 0) {
- need_numeric_port_hack_=1;
- }
- if (ai2 && ai2->ai_protocol == 0) {
- need_socktype_protocol_hack_=1;
- }
-
- if (ai)
- freeaddrinfo(ai);
- if (ai2)
- freeaddrinfo(ai2);
- tested_for_getaddrinfo_hacks=1;
-}
-
-static inline int
-need_numeric_port_hack(void)
-{
- if (!tested_for_getaddrinfo_hacks)
- test_for_getaddrinfo_hacks();
- return need_numeric_port_hack_;
-}
-
-static inline int
-need_socktype_protocol_hack(void)
-{
- if (!tested_for_getaddrinfo_hacks)
- test_for_getaddrinfo_hacks();
- return need_socktype_protocol_hack_;
-}
-
-static void
-apply_numeric_port_hack(int port, struct evutil_addrinfo **ai)
-{
- /* Now we run through the list and set the ports on all of the
- * results where ports would make sense. */
- for ( ; *ai; ai = &(*ai)->ai_next) {
- struct sockaddr *sa = (*ai)->ai_addr;
- if (sa && sa->sa_family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in*)sa;
- sin->sin_port = htons(port);
- } else if (sa && sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
- sin6->sin6_port = htons(port);
- } else {
- /* A numeric port makes no sense here; remove this one
- * from the list. */
- struct evutil_addrinfo *victim = *ai;
- *ai = victim->ai_next;
- victim->ai_next = NULL;
- freeaddrinfo(victim);
- }
- }
-}
-
-static int
-apply_socktype_protocol_hack(struct evutil_addrinfo *ai)
-{
- struct evutil_addrinfo *ai_new;
- for (; ai; ai = ai->ai_next) {
- evutil_getaddrinfo_infer_protocols(ai);
- if (ai->ai_socktype || ai->ai_protocol)
- continue;
- ai_new = mm_malloc(sizeof(*ai_new));
- if (!ai_new)
- return -1;
- memcpy(ai_new, ai, sizeof(*ai_new));
- ai->ai_socktype = SOCK_STREAM;
- ai->ai_protocol = IPPROTO_TCP;
- ai_new->ai_socktype = SOCK_DGRAM;
- ai_new->ai_protocol = IPPROTO_UDP;
-
- ai_new->ai_next = ai->ai_next;
- ai->ai_next = ai_new;
- }
- return 0;
-}
-#endif
-
-int
-evutil_getaddrinfo(const char *nodename, const char *servname,
- const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res)
-{
-#ifdef USE_NATIVE_GETADDRINFO
- struct evutil_addrinfo hints;
- int portnum=-1, need_np_hack, err;
-
- if (hints_in) {
- memcpy(&hints, hints_in, sizeof(hints));
- } else {
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- }
-
-#ifndef AI_ADDRCONFIG
- /* Not every system has AI_ADDRCONFIG, so fake it. */
- if (hints.ai_family == PF_UNSPEC &&
- (hints.ai_flags & EVUTIL_AI_ADDRCONFIG)) {
- evutil_adjust_hints_for_addrconfig_(&hints);
- }
-#endif
-
-#ifndef AI_NUMERICSERV
- /* Not every system has AI_NUMERICSERV, so fake it. */
- if (hints.ai_flags & EVUTIL_AI_NUMERICSERV) {
- if (servname && parse_numeric_servname(servname)<0)
- return EVUTIL_EAI_NONAME;
- }
-#endif
-
- /* Enough operating systems handle enough common non-resolve
- * cases here weirdly enough that we are better off just
- * overriding them. For example:
- *
- * - Windows doesn't like to infer the protocol from the
- * socket type, or fill in socket or protocol types much at
- * all. It also seems to do its own broken implicit
- * always-on version of AI_ADDRCONFIG that keeps it from
- * ever resolving even a literal IPv6 address when
- * ai_addrtype is PF_UNSPEC.
- */
-#ifdef _WIN32
- {
- int tmp_port;
- err = evutil_getaddrinfo_common_(nodename,servname,&hints,
- res, &tmp_port);
- if (err == 0 ||
- err == EVUTIL_EAI_MEMORY ||
- err == EVUTIL_EAI_NONAME)
- return err;
- /* If we make it here, the system getaddrinfo can
- * have a crack at it. */
- }
-#endif
-
- /* See documentation for need_numeric_port_hack above.*/
- need_np_hack = need_numeric_port_hack() && servname && !hints.ai_socktype
- && ((portnum=parse_numeric_servname(servname)) >= 0);
- if (need_np_hack) {
- if (!nodename)
- return evutil_getaddrinfo_common_(
- NULL,servname,&hints, res, &portnum);
- servname = NULL;
- }
-
- if (need_socktype_protocol_hack()) {
- evutil_getaddrinfo_infer_protocols(&hints);
- }
-
- /* Make sure that we didn't actually steal any AI_FLAGS values that
- * the system is using. (This is a constant expression, and should ge
- * optimized out.)
- *
- * XXXX Turn this into a compile-time failure rather than a run-time
- * failure.
- */
- EVUTIL_ASSERT((ALL_NONNATIVE_AI_FLAGS & ALL_NATIVE_AI_FLAGS) == 0);
-
- /* Clear any flags that only libevent understands. */
- hints.ai_flags &= ~ALL_NONNATIVE_AI_FLAGS;
-
- err = getaddrinfo(nodename, servname, &hints, res);
- if (need_np_hack)
- apply_numeric_port_hack(portnum, res);
-
- if (need_socktype_protocol_hack()) {
- if (apply_socktype_protocol_hack(*res) < 0) {
- evutil_freeaddrinfo(*res);
- *res = NULL;
- return EVUTIL_EAI_MEMORY;
- }
- }
- return err;
-#else
- int port=0, err;
- struct hostent *ent = NULL;
- struct evutil_addrinfo hints;
-
- if (hints_in) {
- memcpy(&hints, hints_in, sizeof(hints));
- } else {
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- }
-
- evutil_adjust_hints_for_addrconfig_(&hints);
-
- err = evutil_getaddrinfo_common_(nodename, servname, &hints, res, &port);
- if (err != EVUTIL_EAI_NEED_RESOLVE) {
- /* We either succeeded or failed. No need to continue */
- return err;
- }
-
- err = 0;
- /* Use any of the various gethostbyname_r variants as available. */
- {
-#ifdef EVENT__HAVE_GETHOSTBYNAME_R_6_ARG
- /* This one is what glibc provides. */
- char buf[2048];
- struct hostent hostent;
- int r;
- r = gethostbyname_r(nodename, &hostent, buf, sizeof(buf), &ent,
- &err);
-#elif defined(EVENT__HAVE_GETHOSTBYNAME_R_5_ARG)
- char buf[2048];
- struct hostent hostent;
- ent = gethostbyname_r(nodename, &hostent, buf, sizeof(buf),
- &err);
-#elif defined(EVENT__HAVE_GETHOSTBYNAME_R_3_ARG)
- struct hostent_data data;
- struct hostent hostent;
- memset(&data, 0, sizeof(data));
- err = gethostbyname_r(nodename, &hostent, &data);
- ent = err ? NULL : &hostent;
-#else
- /* fall back to gethostbyname. */
- /* XXXX This needs a lock everywhere but Windows. */
- ent = gethostbyname(nodename);
-#ifdef _WIN32
- err = WSAGetLastError();
-#else
- err = h_errno;
-#endif
-#endif
-
- /* Now we have either ent or err set. */
- if (!ent) {
- /* XXX is this right for windows ? */
- switch (err) {
- case TRY_AGAIN:
- return EVUTIL_EAI_AGAIN;
- case NO_RECOVERY:
- default:
- return EVUTIL_EAI_FAIL;
- case HOST_NOT_FOUND:
- return EVUTIL_EAI_NONAME;
- case NO_ADDRESS:
-#if NO_DATA != NO_ADDRESS
- case NO_DATA:
-#endif
- return EVUTIL_EAI_NODATA;
- }
- }
-
- if (ent->h_addrtype != hints.ai_family &&
- hints.ai_family != PF_UNSPEC) {
- /* This wasn't the type we were hoping for. Too bad
- * we never had a chance to ask gethostbyname for what
- * we wanted. */
- return EVUTIL_EAI_NONAME;
- }
-
- /* Make sure we got _some_ answers. */
- if (ent->h_length == 0)
- return EVUTIL_EAI_NODATA;
-
- /* If we got an address type we don't know how to make a
- sockaddr for, give up. */
- if (ent->h_addrtype != PF_INET && ent->h_addrtype != PF_INET6)
- return EVUTIL_EAI_FAMILY;
-
- *res = addrinfo_from_hostent(ent, port, &hints);
- if (! *res)
- return EVUTIL_EAI_MEMORY;
- }
-
- return 0;
-#endif
-}
-
-void
-evutil_freeaddrinfo(struct evutil_addrinfo *ai)
-{
-#ifdef EVENT__HAVE_GETADDRINFO
- if (!(ai->ai_flags & EVUTIL_AI_LIBEVENT_ALLOCATED)) {
- freeaddrinfo(ai);
- return;
- }
-#endif
- while (ai) {
- struct evutil_addrinfo *next = ai->ai_next;
- if (ai->ai_canonname)
- mm_free(ai->ai_canonname);
- mm_free(ai);
- ai = next;
- }
-}
-
-static evdns_getaddrinfo_fn evdns_getaddrinfo_impl = NULL;
-
-void
-evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn)
-{
- if (!evdns_getaddrinfo_impl)
- evdns_getaddrinfo_impl = fn;
-}
-
-/* Internal helper function: act like evdns_getaddrinfo if dns_base is set;
- * otherwise do a blocking resolve and pass the result to the callback in the
- * way that evdns_getaddrinfo would.
- */
-int
-evutil_getaddrinfo_async_(struct evdns_base *dns_base,
- const char *nodename, const char *servname,
- const struct evutil_addrinfo *hints_in,
- void (*cb)(int, struct evutil_addrinfo *, void *), void *arg)
-{
- if (dns_base && evdns_getaddrinfo_impl) {
- evdns_getaddrinfo_impl(
- dns_base, nodename, servname, hints_in, cb, arg);
- } else {
- struct evutil_addrinfo *ai=NULL;
- int err;
- err = evutil_getaddrinfo(nodename, servname, hints_in, &ai);
- cb(err, ai, arg);
- }
- return 0;
-}
-
-const char *
-evutil_gai_strerror(int err)
-{
- /* As a sneaky side-benefit, this case statement will get most
- * compilers to tell us if any of the error codes we defined
- * conflict with the platform's native error codes. */
- switch (err) {
- case EVUTIL_EAI_CANCEL:
- return "Request canceled";
- case 0:
- return "No error";
-
- case EVUTIL_EAI_ADDRFAMILY:
- return "address family for nodename not supported";
- case EVUTIL_EAI_AGAIN:
- return "temporary failure in name resolution";
- case EVUTIL_EAI_BADFLAGS:
- return "invalid value for ai_flags";
- case EVUTIL_EAI_FAIL:
- return "non-recoverable failure in name resolution";
- case EVUTIL_EAI_FAMILY:
- return "ai_family not supported";
- case EVUTIL_EAI_MEMORY:
- return "memory allocation failure";
- case EVUTIL_EAI_NODATA:
- return "no address associated with nodename";
- case EVUTIL_EAI_NONAME:
- return "nodename nor servname provided, or not known";
- case EVUTIL_EAI_SERVICE:
- return "servname not supported for ai_socktype";
- case EVUTIL_EAI_SOCKTYPE:
- return "ai_socktype not supported";
- case EVUTIL_EAI_SYSTEM:
- return "system error";
- default:
-#if defined(USE_NATIVE_GETADDRINFO) && defined(_WIN32)
- return gai_strerrorA(err);
-#elif defined(USE_NATIVE_GETADDRINFO)
- return gai_strerror(err);
-#else
- return "Unknown error code";
-#endif
- }
-}
-
-#ifdef _WIN32
-/* destructively remove a trailing line terminator from s */
-static void
-chomp (char *s)
-{
- size_t len;
- if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') {
- s[--len] = 0;
- if (len > 0 && s[len - 1] == '\r')
- s[--len] = 0;
- }
-}
-
-/* FormatMessage returns allocated strings, but evutil_socket_error_to_string
- * is supposed to return a string which is good indefinitely without having
- * to be freed. To make this work without leaking memory, we cache the
- * string the first time FormatMessage is called on a particular error
- * code, and then return the cached string on subsequent calls with the
- * same code. The strings aren't freed until libevent_global_shutdown
- * (or never). We use a linked list to cache the errors, because we
- * only expect there to be a few dozen, and that should be fast enough.
- */
-
-struct cached_sock_errs_entry {
- HT_ENTRY(cached_sock_errs_entry) node;
- DWORD code;
- char *msg; /* allocated with LocalAlloc; free with LocalFree */
-};
-
-static inline unsigned
-hash_cached_sock_errs(const struct cached_sock_errs_entry *e)
-{
- /* Use Murmur3's 32-bit finalizer as an integer hash function */
- DWORD h = e->code;
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
- return h;
-}
-
-static inline int
-eq_cached_sock_errs(const struct cached_sock_errs_entry *a,
- const struct cached_sock_errs_entry *b)
-{
- return a->code == b->code;
-}
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-static void *windows_socket_errors_lock_ = NULL;
-#endif
-
-static HT_HEAD(cached_sock_errs_map, cached_sock_errs_entry)
- windows_socket_errors = HT_INITIALIZER();
-
-HT_PROTOTYPE(cached_sock_errs_map,
- cached_sock_errs_entry,
- node,
- hash_cached_sock_errs,
- eq_cached_sock_errs);
-
-HT_GENERATE(cached_sock_errs_map,
- cached_sock_errs_entry,
- node,
- hash_cached_sock_errs,
- eq_cached_sock_errs,
- 0.5,
- mm_malloc,
- mm_realloc,
- mm_free);
-
-/** Equivalent to strerror, but for windows socket errors. */
-const char *
-evutil_socket_error_to_string(int errcode)
-{
- struct cached_sock_errs_entry *errs, *newerr, find;
- char *msg = NULL;
-
- EVLOCK_LOCK(windows_socket_errors_lock_, 0);
-
- find.code = errcode;
- errs = HT_FIND(cached_sock_errs_map, &windows_socket_errors, &find);
- if (errs) {
- msg = errs->msg;
- goto done;
- }
-
- if (0 != FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_ALLOCATE_BUFFER,
- NULL, errcode, 0, (char *)&msg, 0, NULL))
- chomp (msg); /* because message has trailing newline */
- else {
- size_t len = 50;
- /* use LocalAlloc because FormatMessage does */
- msg = LocalAlloc(LMEM_FIXED, len);
- if (!msg) {
- msg = (char *)"LocalAlloc failed during Winsock error";
- goto done;
- }
- evutil_snprintf(msg, len, "winsock error 0x%08x", errcode);
- }
-
- newerr = (struct cached_sock_errs_entry *)
- mm_malloc(sizeof (struct cached_sock_errs_entry));
-
- if (!newerr) {
- LocalFree(msg);
- msg = (char *)"malloc failed during Winsock error";
- goto done;
- }
-
- newerr->code = errcode;
- newerr->msg = msg;
- HT_INSERT(cached_sock_errs_map, &windows_socket_errors, newerr);
-
- done:
- EVLOCK_UNLOCK(windows_socket_errors_lock_, 0);
-
- return msg;
-}
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-int
-evutil_global_setup_locks_(const int enable_locks)
-{
- EVTHREAD_SETUP_GLOBAL_LOCK(windows_socket_errors_lock_, 0);
- return 0;
-}
-#endif
-
-static void
-evutil_free_sock_err_globals(void)
-{
- struct cached_sock_errs_entry **errs, *tofree;
-
- for (errs = HT_START(cached_sock_errs_map, &windows_socket_errors)
- ; errs; ) {
- tofree = *errs;
- errs = HT_NEXT_RMV(cached_sock_errs_map,
- &windows_socket_errors,
- errs);
- LocalFree(tofree->msg);
- mm_free(tofree);
- }
-
- HT_CLEAR(cached_sock_errs_map, &windows_socket_errors);
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (windows_socket_errors_lock_ != NULL) {
- EVTHREAD_FREE_LOCK(windows_socket_errors_lock_, 0);
- windows_socket_errors_lock_ = NULL;
- }
-#endif
-}
-
-#else
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-int
-evutil_global_setup_locks_(const int enable_locks)
-{
- return 0;
-}
-#endif
-
-static void
-evutil_free_sock_err_globals(void)
-{
-}
-
-#endif
-
-int
-evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
-{
- int r;
- va_list ap;
- va_start(ap, format);
- r = evutil_vsnprintf(buf, buflen, format, ap);
- va_end(ap);
- return r;
-}
-
-int
-evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
-{
- int r;
- if (!buflen)
- return 0;
-#if defined(_MSC_VER) || defined(_WIN32)
- r = _vsnprintf(buf, buflen, format, ap);
- if (r < 0)
- r = _vscprintf(format, ap);
-#elif defined(sgi)
- /* Make sure we always use the correct vsnprintf on IRIX */
- extern int _xpg5_vsnprintf(char * __restrict,
- __SGI_LIBC_NAMESPACE_QUALIFIER size_t,
- const char * __restrict, /* va_list */ char *);
-
- r = _xpg5_vsnprintf(buf, buflen, format, ap);
-#else
- r = vsnprintf(buf, buflen, format, ap);
-#endif
- buf[buflen-1] = '\0';
- return r;
-}
-
-#define USE_INTERNAL_NTOP
-#define USE_INTERNAL_PTON
-
-const char *
-evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
-{
-#if defined(EVENT__HAVE_INET_NTOP) && !defined(USE_INTERNAL_NTOP)
- return inet_ntop(af, src, dst, len);
-#else
- if (af == AF_INET) {
- const struct in_addr *in = src;
- const ev_uint32_t a = ntohl(in->s_addr);
- int r;
- r = evutil_snprintf(dst, len, "%d.%d.%d.%d",
- (int)(ev_uint8_t)((a>>24)&0xff),
- (int)(ev_uint8_t)((a>>16)&0xff),
- (int)(ev_uint8_t)((a>>8 )&0xff),
- (int)(ev_uint8_t)((a )&0xff));
- if (r<0||(size_t)r>=len)
- return NULL;
- else
- return dst;
-#ifdef AF_INET6
- } else if (af == AF_INET6) {
- const struct in6_addr *addr = src;
- char buf[64], *cp;
- int longestGapLen = 0, longestGapPos = -1, i,
- curGapPos = -1, curGapLen = 0;
- ev_uint16_t words[8];
- for (i = 0; i < 8; ++i) {
- words[i] =
- (((ev_uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
- }
- if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
- words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
- (words[5] == 0xffff))) {
- /* This is an IPv4 address. */
- if (words[5] == 0) {
- evutil_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
- addr->s6_addr[12], addr->s6_addr[13],
- addr->s6_addr[14], addr->s6_addr[15]);
- } else {
- evutil_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
- addr->s6_addr[12], addr->s6_addr[13],
- addr->s6_addr[14], addr->s6_addr[15]);
- }
- if (strlen(buf) > len)
- return NULL;
- strlcpy(dst, buf, len);
- return dst;
- }
- i = 0;
- while (i < 8) {
- if (words[i] == 0) {
- curGapPos = i++;
- curGapLen = 1;
- while (i<8 && words[i] == 0) {
- ++i; ++curGapLen;
- }
- if (curGapLen > longestGapLen) {
- longestGapPos = curGapPos;
- longestGapLen = curGapLen;
- }
- } else {
- ++i;
- }
- }
- if (longestGapLen<=1)
- longestGapPos = -1;
-
- cp = buf;
- for (i = 0; i < 8; ++i) {
- if (words[i] == 0 && longestGapPos == i) {
- if (i == 0)
- *cp++ = ':';
- *cp++ = ':';
- while (i < 8 && words[i] == 0)
- ++i;
- --i; /* to compensate for loop increment. */
- } else {
- evutil_snprintf(cp,
- sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
- cp += strlen(cp);
- if (i != 7)
- *cp++ = ':';
- }
- }
- *cp = '\0';
- if (strlen(buf) > len)
- return NULL;
- strlcpy(dst, buf, len);
- return dst;
-#endif
- } else {
- return NULL;
- }
-#endif
-}
-
-int
-evutil_inet_pton(int af, const char *src, void *dst)
-{
-#if defined(EVENT__HAVE_INET_PTON) && !defined(USE_INTERNAL_PTON)
- return inet_pton(af, src, dst);
-#else
- if (af == AF_INET) {
- unsigned a,b,c,d;
- char more;
- struct in_addr *addr = dst;
- if (sscanf(src, "%u.%u.%u.%u%c", &a,&b,&c,&d,&more) != 4)
- return 0;
- if (a > 255) return 0;
- if (b > 255) return 0;
- if (c > 255) return 0;
- if (d > 255) return 0;
- addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
- return 1;
-#ifdef AF_INET6
- } else if (af == AF_INET6) {
- struct in6_addr *out = dst;
- ev_uint16_t words[8];
- int gapPos = -1, i, setWords=0;
- const char *dot = strchr(src, '.');
- const char *eow; /* end of words. */
- if (dot == src)
- return 0;
- else if (!dot)
- eow = src+strlen(src);
- else {
- unsigned byte1,byte2,byte3,byte4;
- char more;
- for (eow = dot-1; eow >= src && EVUTIL_ISDIGIT_(*eow); --eow)
- ;
- ++eow;
-
- /* We use "scanf" because some platform inet_aton()s are too lax
- * about IPv4 addresses of the form "1.2.3" */
- if (sscanf(eow, "%u.%u.%u.%u%c",
- &byte1,&byte2,&byte3,&byte4,&more) != 4)
- return 0;
-
- if (byte1 > 255 ||
- byte2 > 255 ||
- byte3 > 255 ||
- byte4 > 255)
- return 0;
-
- words[6] = (byte1<<8) | byte2;
- words[7] = (byte3<<8) | byte4;
- setWords += 2;
- }
-
- i = 0;
- while (src < eow) {
- if (i > 7)
- return 0;
- if (EVUTIL_ISXDIGIT_(*src)) {
- char *next;
- long r = strtol(src, &next, 16);
- if (next > 4+src)
- return 0;
- if (next == src)
- return 0;
- if (r<0 || r>65536)
- return 0;
-
- words[i++] = (ev_uint16_t)r;
- setWords++;
- src = next;
- if (*src != ':' && src != eow)
- return 0;
- ++src;
- } else if (*src == ':' && i > 0 && gapPos==-1) {
- gapPos = i;
- ++src;
- } else if (*src == ':' && i == 0 && src[1] == ':' && gapPos==-1) {
- gapPos = i;
- src += 2;
- } else {
- return 0;
- }
- }
-
- if (setWords > 8 ||
- (setWords == 8 && gapPos != -1) ||
- (setWords < 8 && gapPos == -1))
- return 0;
-
- if (gapPos >= 0) {
- int nToMove = setWords - (dot ? 2 : 0) - gapPos;
- int gapLen = 8 - setWords;
- /* assert(nToMove >= 0); */
- if (nToMove < 0)
- return -1; /* should be impossible */
- memmove(&words[gapPos+gapLen], &words[gapPos],
- sizeof(ev_uint16_t)*nToMove);
- memset(&words[gapPos], 0, sizeof(ev_uint16_t)*gapLen);
- }
- for (i = 0; i < 8; ++i) {
- out->s6_addr[2*i ] = words[i] >> 8;
- out->s6_addr[2*i+1] = words[i] & 0xff;
- }
-
- return 1;
-#endif
- } else {
- return -1;
- }
-#endif
-}
-
-int
-evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *outlen)
-{
- int port;
- char buf[128];
- const char *cp, *addr_part, *port_part;
- int is_ipv6;
- /* recognized formats are:
- * [ipv6]:port
- * ipv6
- * [ipv6]
- * ipv4:port
- * ipv4
- */
-
- cp = strchr(ip_as_string, ':');
- if (*ip_as_string == '[') {
- size_t len;
- if (!(cp = strchr(ip_as_string, ']'))) {
- return -1;
- }
- len = ( cp-(ip_as_string + 1) );
- if (len > sizeof(buf)-1) {
- return -1;
- }
- memcpy(buf, ip_as_string+1, len);
- buf[len] = '\0';
- addr_part = buf;
- if (cp[1] == ':')
- port_part = cp+2;
- else
- port_part = NULL;
- is_ipv6 = 1;
- } else if (cp && strchr(cp+1, ':')) {
- is_ipv6 = 1;
- addr_part = ip_as_string;
- port_part = NULL;
- } else if (cp) {
- is_ipv6 = 0;
- if (cp - ip_as_string > (int)sizeof(buf)-1) {
- return -1;
- }
- memcpy(buf, ip_as_string, cp-ip_as_string);
- buf[cp-ip_as_string] = '\0';
- addr_part = buf;
- port_part = cp+1;
- } else {
- addr_part = ip_as_string;
- port_part = NULL;
- is_ipv6 = 0;
- }
-
- if (port_part == NULL) {
- port = 0;
- } else {
- port = atoi(port_part);
- if (port <= 0 || port > 65535) {
- return -1;
- }
- }
-
- if (!addr_part)
- return -1; /* Should be impossible. */
-#ifdef AF_INET6
- if (is_ipv6)
- {
- struct sockaddr_in6 sin6;
- memset(&sin6, 0, sizeof(sin6));
-#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
- sin6.sin6_len = sizeof(sin6);
-#endif
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(port);
- if (1 != evutil_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr))
- return -1;
- if ((int)sizeof(sin6) > *outlen)
- return -1;
- memset(out, 0, *outlen);
- memcpy(out, &sin6, sizeof(sin6));
- *outlen = sizeof(sin6);
- return 0;
- }
- else
-#endif
- {
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof(sin));
-#ifdef EVENT__HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- sin.sin_len = sizeof(sin);
-#endif
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
- if (1 != evutil_inet_pton(AF_INET, addr_part, &sin.sin_addr))
- return -1;
- if ((int)sizeof(sin) > *outlen)
- return -1;
- memset(out, 0, *outlen);
- memcpy(out, &sin, sizeof(sin));
- *outlen = sizeof(sin);
- return 0;
- }
-}
-
-const char *
-evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen)
-{
- char b[128];
- const char *res=NULL;
- int port;
- if (sa->sa_family == AF_INET) {
- const struct sockaddr_in *sin = (const struct sockaddr_in*)sa;
- res = evutil_inet_ntop(AF_INET, &sin->sin_addr,b,sizeof(b));
- port = ntohs(sin->sin_port);
- if (res) {
- evutil_snprintf(out, outlen, "%s:%d", b, port);
- return out;
- }
- } else if (sa->sa_family == AF_INET6) {
- const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6*)sa;
- res = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr,b,sizeof(b));
- port = ntohs(sin6->sin6_port);
- if (res) {
- evutil_snprintf(out, outlen, "[%s]:%d", b, port);
- return out;
- }
- }
-
- evutil_snprintf(out, outlen, "<addr with socktype %d>",
- (int)sa->sa_family);
- return out;
-}
-
-int
-evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
- int include_port)
-{
- int r;
- if (0 != (r = (sa1->sa_family - sa2->sa_family)))
- return r;
-
- if (sa1->sa_family == AF_INET) {
- const struct sockaddr_in *sin1, *sin2;
- sin1 = (const struct sockaddr_in *)sa1;
- sin2 = (const struct sockaddr_in *)sa2;
- if (sin1->sin_addr.s_addr < sin2->sin_addr.s_addr)
- return -1;
- else if (sin1->sin_addr.s_addr > sin2->sin_addr.s_addr)
- return 1;
- else if (include_port &&
- (r = ((int)sin1->sin_port - (int)sin2->sin_port)))
- return r;
- else
- return 0;
- }
-#ifdef AF_INET6
- else if (sa1->sa_family == AF_INET6) {
- const struct sockaddr_in6 *sin1, *sin2;
- sin1 = (const struct sockaddr_in6 *)sa1;
- sin2 = (const struct sockaddr_in6 *)sa2;
- if ((r = memcmp(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16)))
- return r;
- else if (include_port &&
- (r = ((int)sin1->sin6_port - (int)sin2->sin6_port)))
- return r;
- else
- return 0;
- }
-#endif
- return 1;
-}
-
-/* Tables to implement ctypes-replacement EVUTIL_IS*() functions. Each table
- * has 256 bits to look up whether a character is in some set or not. This
- * fails on non-ASCII platforms, but so does every other place where we
- * take a char and write it onto the network.
- **/
-static const ev_uint32_t EVUTIL_ISALPHA_TABLE[8] =
- { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
-static const ev_uint32_t EVUTIL_ISALNUM_TABLE[8] =
- { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 };
-static const ev_uint32_t EVUTIL_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 };
-static const ev_uint32_t EVUTIL_ISXDIGIT_TABLE[8] =
- { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 };
-static const ev_uint32_t EVUTIL_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 };
-static const ev_uint32_t EVUTIL_ISPRINT_TABLE[8] =
- { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 };
-static const ev_uint32_t EVUTIL_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 };
-static const ev_uint32_t EVUTIL_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
-/* Upper-casing and lowercasing tables to map characters to upper/lowercase
- * equivalents. */
-static const unsigned char EVUTIL_TOUPPER_TABLE[256] = {
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
- 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
- 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
- 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
- 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
- 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
- 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
-};
-static const unsigned char EVUTIL_TOLOWER_TABLE[256] = {
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
- 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
- 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
- 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
- 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95,
- 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
- 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
-};
-
-#define IMPL_CTYPE_FN(name) \
- int EVUTIL_##name##_(char c) { \
- ev_uint8_t u = c; \
- return !!(EVUTIL_##name##_TABLE[(u >> 5) & 7] & (1 << (u & 31))); \
- }
-IMPL_CTYPE_FN(ISALPHA)
-IMPL_CTYPE_FN(ISALNUM)
-IMPL_CTYPE_FN(ISSPACE)
-IMPL_CTYPE_FN(ISDIGIT)
-IMPL_CTYPE_FN(ISXDIGIT)
-IMPL_CTYPE_FN(ISPRINT)
-IMPL_CTYPE_FN(ISLOWER)
-IMPL_CTYPE_FN(ISUPPER)
-
-char EVUTIL_TOLOWER_(char c)
-{
- return ((char)EVUTIL_TOLOWER_TABLE[(ev_uint8_t)c]);
-}
-char EVUTIL_TOUPPER_(char c)
-{
- return ((char)EVUTIL_TOUPPER_TABLE[(ev_uint8_t)c]);
-}
-int
-evutil_ascii_strcasecmp(const char *s1, const char *s2)
-{
- char c1, c2;
- while (1) {
- c1 = EVUTIL_TOLOWER_(*s1++);
- c2 = EVUTIL_TOLOWER_(*s2++);
- if (c1 < c2)
- return -1;
- else if (c1 > c2)
- return 1;
- else if (c1 == 0)
- return 0;
- }
-}
-int evutil_ascii_strncasecmp(const char *s1, const char *s2, size_t n)
-{
- char c1, c2;
- while (n--) {
- c1 = EVUTIL_TOLOWER_(*s1++);
- c2 = EVUTIL_TOLOWER_(*s2++);
- if (c1 < c2)
- return -1;
- else if (c1 > c2)
- return 1;
- else if (c1 == 0)
- return 0;
- }
- return 0;
-}
-
-void
-evutil_rtrim_lws_(char *str)
-{
- char *cp;
-
- if (str == NULL)
- return;
-
- if ((cp = strchr(str, '\0')) == NULL || (cp == str))
- return;
-
- --cp;
-
- while (*cp == ' ' || *cp == '\t') {
- *cp = '\0';
- if (cp == str)
- break;
- --cp;
- }
-}
-
-static int
-evutil_issetugid(void)
-{
-#ifdef EVENT__HAVE_ISSETUGID
- return issetugid();
-#else
-
-#ifdef EVENT__HAVE_GETEUID
- if (getuid() != geteuid())
- return 1;
-#endif
-#ifdef EVENT__HAVE_GETEGID
- if (getgid() != getegid())
- return 1;
-#endif
- return 0;
-#endif
-}
-
-const char *
-evutil_getenv_(const char *varname)
-{
- if (evutil_issetugid())
- return NULL;
-
- return getenv(varname);
-}
-
-ev_uint32_t
-evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed)
-{
- if (seed == 0) {
- struct timeval tv;
- evutil_gettimeofday(&tv, NULL);
- seed = (ev_uint32_t)tv.tv_sec + (ev_uint32_t)tv.tv_usec;
-#ifdef _WIN32
- seed += (ev_uint32_t) _getpid();
-#else
- seed += (ev_uint32_t) getpid();
-#endif
- }
- state->seed = seed;
- return seed;
-}
-
-ev_int32_t
-evutil_weakrand_(struct evutil_weakrand_state *state)
-{
- /* This RNG implementation is a linear congruential generator, with
- * modulus 2^31, multiplier 1103515245, and addend 12345. It's also
- * used by OpenBSD, and by Glibc's TYPE_0 RNG.
- *
- * The linear congruential generator is not an industrial-strength
- * RNG! It's fast, but it can have higher-order patterns. Notably,
- * the low bits tend to have periodicity.
- */
- state->seed = ((state->seed) * 1103515245 + 12345) & 0x7fffffff;
- return (ev_int32_t)(state->seed);
-}
-
-ev_int32_t
-evutil_weakrand_range_(struct evutil_weakrand_state *state, ev_int32_t top)
-{
- ev_int32_t divisor, result;
-
- /* We can't just do weakrand() % top, since the low bits of the LCG
- * are less random than the high ones. (Specifically, since the LCG
- * modulus is 2^N, every 2^m for m<N will divide the modulus, and so
- * therefore the low m bits of the LCG will have period 2^m.) */
- divisor = EVUTIL_WEAKRAND_MAX / top;
- do {
- result = evutil_weakrand_(state) / divisor;
- } while (result >= top);
- return result;
-}
-
-/**
- * Volatile pointer to memset: we use this to keep the compiler from
- * eliminating our call to memset.
- */
-void * (*volatile evutil_memset_volatile_)(void *, int, size_t) = memset;
-
-void
-evutil_memclear_(void *mem, size_t len)
-{
- evutil_memset_volatile_(mem, 0, len);
-}
-
-int
-evutil_sockaddr_is_loopback_(const struct sockaddr *addr)
-{
- static const char LOOPBACK_S6[16] =
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in *)addr;
- return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
- } else if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
- return !memcmp(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
- }
- return 0;
-}
-
-int
-evutil_hex_char_to_int_(char c)
-{
- switch(c)
- {
- case '0': return 0;
- case '1': return 1;
- case '2': return 2;
- case '3': return 3;
- case '4': return 4;
- case '5': return 5;
- case '6': return 6;
- case '7': return 7;
- case '8': return 8;
- case '9': return 9;
- case 'A': case 'a': return 10;
- case 'B': case 'b': return 11;
- case 'C': case 'c': return 12;
- case 'D': case 'd': return 13;
- case 'E': case 'e': return 14;
- case 'F': case 'f': return 15;
- }
- return -1;
-}
-
-#ifdef _WIN32
-HMODULE
-evutil_load_windows_system_library_(const wchar_t *library_name)
-{
- wchar_t path[MAX_PATH];
- unsigned n;
- n = GetSystemDirectory(path, MAX_PATH);
- if (n == 0 || n + wcslen(library_name) + 2 >= MAX_PATH)
- return 0;
- wcscat(path, TEXT("\\"));
- wcscat(path, library_name);
- return LoadLibrary(path);
-}
-#endif
-
-/* Internal wrapper around 'socket' to provide Linux-style support for
- * syscall-saving methods where available.
- *
- * In addition to regular socket behavior, you can use a bitwise or to set the
- * flags EVUTIL_SOCK_NONBLOCK and EVUTIL_SOCK_CLOEXEC in the 'type' argument,
- * to make the socket nonblocking or close-on-exec with as few syscalls as
- * possible.
- */
-evutil_socket_t
-evutil_socket_(int domain, int type, int protocol)
-{
- evutil_socket_t r;
-#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
- r = socket(domain, type, protocol);
- if (r >= 0)
- return r;
- else if ((type & (SOCK_NONBLOCK|SOCK_CLOEXEC)) == 0)
- return -1;
-#endif
-#define SOCKET_TYPE_MASK (~(EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC))
- r = socket(domain, type & SOCKET_TYPE_MASK, protocol);
- if (r < 0)
- return -1;
- if (type & EVUTIL_SOCK_NONBLOCK) {
- if (evutil_fast_socket_nonblocking(r) < 0) {
- evutil_closesocket(r);
- return -1;
- }
- }
- if (type & EVUTIL_SOCK_CLOEXEC) {
- if (evutil_fast_socket_closeonexec(r) < 0) {
- evutil_closesocket(r);
- return -1;
- }
- }
- return r;
-}
-
-/* Internal wrapper around 'accept' or 'accept4' to provide Linux-style
- * support for syscall-saving methods where available.
- *
- * In addition to regular accept behavior, you can set one or more of flags
- * EVUTIL_SOCK_NONBLOCK and EVUTIL_SOCK_CLOEXEC in the 'flags' argument, to
- * make the socket nonblocking or close-on-exec with as few syscalls as
- * possible.
- */
-evutil_socket_t
-evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
- ev_socklen_t *addrlen, int flags)
-{
- evutil_socket_t result;
-#if defined(EVENT__HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
- result = accept4(sockfd, addr, addrlen, flags);
- if (result >= 0 || (errno != EINVAL && errno != ENOSYS)) {
- /* A nonnegative result means that we succeeded, so return.
- * Failing with EINVAL means that an option wasn't supported,
- * and failing with ENOSYS means that the syscall wasn't
- * there: in those cases we want to fall back. Otherwise, we
- * got a real error, and we should return. */
- return result;
- }
-#endif
- result = accept(sockfd, addr, addrlen);
- if (result < 0)
- return result;
-
- if (flags & EVUTIL_SOCK_CLOEXEC) {
- if (evutil_fast_socket_closeonexec(result) < 0) {
- evutil_closesocket(result);
- return -1;
- }
- }
- if (flags & EVUTIL_SOCK_NONBLOCK) {
- if (evutil_fast_socket_nonblocking(result) < 0) {
- evutil_closesocket(result);
- return -1;
- }
- }
- return result;
-}
-
-/* Internal function: Set fd[0] and fd[1] to a pair of fds such that writes on
- * fd[0] get read from fd[1]. Make both fds nonblocking and close-on-exec.
- * Return 0 on success, -1 on failure.
- */
-int
-evutil_make_internal_pipe_(evutil_socket_t fd[2])
-{
- /*
- Making the second socket nonblocking is a bit subtle, given that we
- ignore any EAGAIN returns when writing to it, and you don't usally
- do that for a nonblocking socket. But if the kernel gives us EAGAIN,
- then there's no need to add any more data to the buffer, since
- the main thread is already either about to wake up and drain it,
- or woken up and in the process of draining it.
- */
-
-#if defined(EVENT__HAVE_PIPE2)
- if (pipe2(fd, O_NONBLOCK|O_CLOEXEC) == 0)
- return 0;
-#endif
-#if defined(EVENT__HAVE_PIPE)
- if (pipe(fd) == 0) {
- if (evutil_fast_socket_nonblocking(fd[0]) < 0 ||
- evutil_fast_socket_nonblocking(fd[1]) < 0 ||
- evutil_fast_socket_closeonexec(fd[0]) < 0 ||
- evutil_fast_socket_closeonexec(fd[1]) < 0) {
- close(fd[0]);
- close(fd[1]);
- fd[0] = fd[1] = -1;
- return -1;
- }
- return 0;
- } else {
- event_warn("%s: pipe", __func__);
- }
-#endif
-
-#ifdef _WIN32
-#define LOCAL_SOCKETPAIR_AF AF_INET
-#else
-#define LOCAL_SOCKETPAIR_AF AF_UNIX
-#endif
- if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, fd) == 0) {
- if (evutil_fast_socket_nonblocking(fd[0]) < 0 ||
- evutil_fast_socket_nonblocking(fd[1]) < 0 ||
- evutil_fast_socket_closeonexec(fd[0]) < 0 ||
- evutil_fast_socket_closeonexec(fd[1]) < 0) {
- evutil_closesocket(fd[0]);
- evutil_closesocket(fd[1]);
- fd[0] = fd[1] = -1;
- return -1;
- }
- return 0;
- }
- fd[0] = fd[1] = -1;
- return -1;
-}
-
-/* Wrapper around eventfd on systems that provide it. Unlike the system
- * eventfd, it always supports EVUTIL_EFD_CLOEXEC and EVUTIL_EFD_NONBLOCK as
- * flags. Returns -1 on error or if eventfd is not supported.
- */
-evutil_socket_t
-evutil_eventfd_(unsigned initval, int flags)
-{
-#if defined(EVENT__HAVE_EVENTFD) && defined(EVENT__HAVE_SYS_EVENTFD_H)
- int r;
-#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
- r = eventfd(initval, flags);
- if (r >= 0 || flags == 0)
- return r;
-#endif
- r = eventfd(initval, 0);
- if (r < 0)
- return r;
- if (flags & EVUTIL_EFD_CLOEXEC) {
- if (evutil_fast_socket_closeonexec(r) < 0) {
- evutil_closesocket(r);
- return -1;
- }
- }
- if (flags & EVUTIL_EFD_NONBLOCK) {
- if (evutil_fast_socket_nonblocking(r) < 0) {
- evutil_closesocket(r);
- return -1;
- }
- }
- return r;
-#else
- return -1;
-#endif
-}
-
-void
-evutil_free_globals_(void)
-{
- evutil_free_secure_rng_globals_();
- evutil_free_sock_err_globals();
-}
diff --git a/libs/libevent/src/evutil_rand.c b/libs/libevent/src/evutil_rand.c
deleted file mode 100644
index 0402772db3..0000000000
--- a/libs/libevent/src/evutil_rand.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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.
- */
-
-/* This file has our secure PRNG code. On platforms that have arc4random(),
- * we just use that. Otherwise, we include arc4random.c as a bunch of static
- * functions, and wrap it lightly. We don't expose the arc4random*() APIs
- * because A) they aren't in our namespace, and B) it's not nice to name your
- * APIs after their implementations. We keep them in a separate file
- * so that other people can rip it out and use it for whatever.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <limits.h>
-
-#include "util-internal.h"
-#include "evthread-internal.h"
-
-#ifdef EVENT__HAVE_ARC4RANDOM
-#include <stdlib.h>
-#include <string.h>
-int
-evutil_secure_rng_set_urandom_device_file(char *fname)
-{
- (void) fname;
- return -1;
-}
-int
-evutil_secure_rng_init(void)
-{
- /* call arc4random() now to force it to self-initialize */
- (void) arc4random();
- return 0;
-}
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-int
-evutil_secure_rng_global_setup_locks_(const int enable_locks)
-{
- return 0;
-}
-#endif
-static void
-evutil_free_secure_rng_globals_locks(void)
-{
-}
-
-static void
-ev_arc4random_buf(void *buf, size_t n)
-{
-#if defined(EVENT__HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__)
- arc4random_buf(buf, n);
- return;
-#else
- unsigned char *b = buf;
-
-#if defined(EVENT__HAVE_ARC4RANDOM_BUF)
- /* OSX 10.7 introducd arc4random_buf, so if you build your program
- * there, you'll get surprised when older versions of OSX fail to run.
- * To solve this, we can check whether the function pointer is set,
- * and fall back otherwise. (OSX does this using some linker
- * trickery.)
- */
- {
- void (*tptr)(void *,size_t) =
- (void (*)(void*,size_t))arc4random_buf;
- if (tptr != NULL) {
- arc4random_buf(buf, n);
- return;
- }
- }
-#endif
- /* Make sure that we start out with b at a 4-byte alignment; plenty
- * of CPUs care about this for 32-bit access. */
- if (n >= 4 && ((ev_uintptr_t)b) & 3) {
- ev_uint32_t u = arc4random();
- int n_bytes = 4 - (((ev_uintptr_t)b) & 3);
- memcpy(b, &u, n_bytes);
- b += n_bytes;
- n -= n_bytes;
- }
- while (n >= 4) {
- *(ev_uint32_t*)b = arc4random();
- b += 4;
- n -= 4;
- }
- if (n) {
- ev_uint32_t u = arc4random();
- memcpy(b, &u, n);
- }
-#endif
-}
-
-#else /* !EVENT__HAVE_ARC4RANDOM { */
-
-#ifdef EVENT__ssize_t
-#define ssize_t EVENT__ssize_t
-#endif
-#define ARC4RANDOM_EXPORT static
-#define ARC4_LOCK_() EVLOCK_LOCK(arc4rand_lock, 0)
-#define ARC4_UNLOCK_() EVLOCK_UNLOCK(arc4rand_lock, 0)
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-static void *arc4rand_lock;
-#endif
-
-#define ARC4RANDOM_UINT32 ev_uint32_t
-#define ARC4RANDOM_NOSTIR
-#define ARC4RANDOM_NORANDOM
-#define ARC4RANDOM_NOUNIFORM
-
-#include "./arc4random.cxx"
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-int
-evutil_secure_rng_global_setup_locks_(const int enable_locks)
-{
- EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0);
- return 0;
-}
-#endif
-
-static void
-evutil_free_secure_rng_globals_locks(void)
-{
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (arc4rand_lock != NULL) {
- EVTHREAD_FREE_LOCK(arc4rand_lock, 0);
- arc4rand_lock = NULL;
- }
-#endif
- return;
-}
-
-int
-evutil_secure_rng_set_urandom_device_file(char *fname)
-{
-#ifdef TRY_SEED_URANDOM
- ARC4_LOCK_();
- arc4random_urandom_filename = fname;
- ARC4_UNLOCK_();
-#endif
- return 0;
-}
-
-int
-evutil_secure_rng_init(void)
-{
- int val;
-
- ARC4_LOCK_();
- if (!arc4_seeded_ok)
- arc4_stir();
- val = arc4_seeded_ok ? 0 : -1;
- ARC4_UNLOCK_();
- return val;
-}
-
-static void
-ev_arc4random_buf(void *buf, size_t n)
-{
- arc4random_buf(buf, n);
-}
-
-#endif /* } !EVENT__HAVE_ARC4RANDOM */
-
-void
-evutil_secure_rng_get_bytes(void *buf, size_t n)
-{
- ev_arc4random_buf(buf, n);
-}
-
-void
-evutil_secure_rng_add_bytes(const char *buf, size_t n)
-{
- arc4random_addrandom((unsigned char*)buf,
- n>(size_t)INT_MAX ? INT_MAX : (int)n);
-}
-
-void
-evutil_free_secure_rng_globals_(void)
-{
- evutil_free_secure_rng_globals_locks();
-}
diff --git a/libs/libevent/src/evutil_time.c b/libs/libevent/src/evutil_time.c
deleted file mode 100644
index 8f53c66b68..0000000000
--- a/libs/libevent/src/evutil_time.c
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#endif
-
-#include <sys/types.h>
-#ifdef EVENT__HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <errno.h>
-#include <limits.h>
-#ifndef EVENT__HAVE_GETTIMEOFDAY
-#include <sys/timeb.h>
-#endif
-#if !defined(EVENT__HAVE_NANOSLEEP) && !defined(EVENT_HAVE_USLEEP) && \
- !defined(_WIN32)
-#include <sys/select.h>
-#endif
-#include <time.h>
-#include <sys/stat.h>
-#include <string.h>
-
-#include "event2/util.h"
-#include "util-internal.h"
-#include "log-internal.h"
-#include "mm-internal.h"
-
-#ifndef EVENT__HAVE_GETTIMEOFDAY
-/* No gettimeofday; this must be windows. */
-int
-evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
-{
-#ifdef _MSC_VER
-#define U64_LITERAL(n) n##ui64
-#else
-#define U64_LITERAL(n) n##llu
-#endif
-
- /* Conversion logic taken from Tor, which in turn took it
- * from Perl. GetSystemTimeAsFileTime returns its value as
- * an unaligned (!) 64-bit value containing the number of
- * 100-nanosecond intervals since 1 January 1601 UTC. */
-#define EPOCH_BIAS U64_LITERAL(116444736000000000)
-#define UNITS_PER_SEC U64_LITERAL(10000000)
-#define USEC_PER_SEC U64_LITERAL(1000000)
-#define UNITS_PER_USEC U64_LITERAL(10)
- union {
- FILETIME ft_ft;
- ev_uint64_t ft_64;
- } ft;
-
- if (tv == NULL)
- return -1;
-
- GetSystemTimeAsFileTime(&ft.ft_ft);
-
- if (EVUTIL_UNLIKELY(ft.ft_64 < EPOCH_BIAS)) {
- /* Time before the unix epoch. */
- return -1;
- }
- ft.ft_64 -= EPOCH_BIAS;
- tv->tv_sec = (long) (ft.ft_64 / UNITS_PER_SEC);
- tv->tv_usec = (long) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
- return 0;
-}
-#endif
-
-#define MAX_SECONDS_IN_MSEC_LONG \
- (((LONG_MAX) - 999) / 1000)
-
-long
-evutil_tv_to_msec_(const struct timeval *tv)
-{
- if (tv->tv_usec > 1000000 || tv->tv_sec > MAX_SECONDS_IN_MSEC_LONG)
- return -1;
-
- return (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
-}
-
-/*
- Replacement for usleep on platforms that don't have one. Not guaranteed to
- be any more finegrained than 1 msec.
- */
-void
-evutil_usleep_(const struct timeval *tv)
-{
- if (!tv)
- return;
-#if defined(_WIN32)
- {
- long msec = evutil_tv_to_msec_(tv);
- Sleep((DWORD)msec);
- }
-#elif defined(EVENT__HAVE_NANOSLEEP)
- {
- struct timespec ts;
- ts.tv_sec = tv->tv_sec;
- ts.tv_nsec = tv->tv_usec*1000;
- nanosleep(&ts, NULL);
- }
-#elif defined(EVENT__HAVE_USLEEP)
- /* Some systems don't like to usleep more than 999999 usec */
- sleep(tv->tv_sec);
- usleep(tv->tv_usec);
-#else
- select(0, NULL, NULL, NULL, tv);
-#endif
-}
-
-/*
- This function assumes it's called repeatedly with a
- not-actually-so-monotonic time source whose outputs are in 'tv'. It
- implements a trivial ratcheting mechanism so that the values never go
- backwards.
- */
-static void
-adjust_monotonic_time(struct evutil_monotonic_timer *base,
- struct timeval *tv)
-{
- evutil_timeradd(tv, &base->adjust_monotonic_clock, tv);
-
- if (evutil_timercmp(tv, &base->last_time, <)) {
- /* Guess it wasn't monotonic after all. */
- struct timeval adjust;
- evutil_timersub(&base->last_time, tv, &adjust);
- evutil_timeradd(&adjust, &base->adjust_monotonic_clock,
- &base->adjust_monotonic_clock);
- *tv = base->last_time;
- }
- base->last_time = *tv;
-}
-
-/*
- Allocate a new struct evutil_monotonic_timer
- */
-struct evutil_monotonic_timer *
-evutil_monotonic_timer_new(void)
-{
- struct evutil_monotonic_timer *p = NULL;
-
- p = mm_malloc(sizeof(*p));
- if (!p) goto done;
-
- memset(p, 0, sizeof(*p));
-
- done:
- return p;
-}
-
-/*
- Free a struct evutil_monotonic_timer
- */
-void
-evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer)
-{
- if (timer) {
- mm_free(timer);
- }
-}
-
-/*
- Set up a struct evutil_monotonic_timer for initial use
- */
-int
-evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer,
- int flags)
-{
- return evutil_configure_monotonic_time_(timer, flags);
-}
-
-/*
- Query the current monotonic time
- */
-int
-evutil_gettime_monotonic(struct evutil_monotonic_timer *timer,
- struct timeval *tp)
-{
- return evutil_gettime_monotonic_(timer, tp);
-}
-
-
-#if defined(HAVE_POSIX_MONOTONIC)
-/* =====
- The POSIX clock_gettime() interface provides a few ways to get at a
- monotonic clock. CLOCK_MONOTONIC is most widely supported. Linux also
- provides a CLOCK_MONOTONIC_COARSE with accuracy of about 1-4 msec.
-
- On all platforms I'm aware of, CLOCK_MONOTONIC really is monotonic.
- Platforms don't agree about whether it should jump on a sleep/resume.
- */
-
-int
-evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int flags)
-{
- /* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris. You need to
- * check for it at runtime, because some older kernel versions won't
- * have it working. */
-#ifdef CLOCK_MONOTONIC_COARSE
- const int precise = flags & EV_MONOT_PRECISE;
-#endif
- const int fallback = flags & EV_MONOT_FALLBACK;
- struct timespec ts;
-
-#ifdef CLOCK_MONOTONIC_COARSE
- if (CLOCK_MONOTONIC_COARSE < 0) {
- /* Technically speaking, nothing keeps CLOCK_* from being
- * negative (as far as I know). This check and the one below
- * make sure that it's safe for us to use -1 as an "unset"
- * value. */
- event_errx(1,"I didn't expect CLOCK_MONOTONIC_COARSE to be < 0");
- }
- if (! precise && ! fallback) {
- if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
- base->monotonic_clock = CLOCK_MONOTONIC_COARSE;
- return 0;
- }
- }
-#endif
- if (!fallback && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
- base->monotonic_clock = CLOCK_MONOTONIC;
- return 0;
- }
-
- if (CLOCK_MONOTONIC < 0) {
- event_errx(1,"I didn't expect CLOCK_MONOTONIC to be < 0");
- }
-
- base->monotonic_clock = -1;
- return 0;
-}
-
-int
-evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
- struct timeval *tp)
-{
- struct timespec ts;
-
- if (base->monotonic_clock < 0) {
- if (evutil_gettimeofday(tp, NULL) < 0)
- return -1;
- adjust_monotonic_time(base, tp);
- return 0;
- }
-
- if (clock_gettime(base->monotonic_clock, &ts) == -1)
- return -1;
- tp->tv_sec = ts.tv_sec;
- tp->tv_usec = ts.tv_nsec / 1000;
-
- return 0;
-}
-#endif
-
-#if defined(HAVE_MACH_MONOTONIC)
-/* ======
- Apple is a little late to the POSIX party. And why not? Instead of
- clock_gettime(), they provide mach_absolute_time(). Its units are not
- fixed; we need to use mach_timebase_info() to get the right functions to
- convert its units into nanoseconds.
-
- To all appearances, mach_absolute_time() seems to be honest-to-goodness
- monotonic. Whether it stops during sleep or not is unspecified in
- principle, and dependent on CPU architecture in practice.
- */
-
-int
-evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int flags)
-{
- const int fallback = flags & EV_MONOT_FALLBACK;
- struct mach_timebase_info mi;
- memset(base, 0, sizeof(*base));
- /* OSX has mach_absolute_time() */
- if (!fallback &&
- mach_timebase_info(&mi) == 0 &&
- mach_absolute_time() != 0) {
- /* mach_timebase_info tells us how to convert
- * mach_absolute_time() into nanoseconds, but we
- * want to use microseconds instead. */
- mi.denom *= 1000;
- memcpy(&base->mach_timebase_units, &mi, sizeof(mi));
- } else {
- base->mach_timebase_units.numer = 0;
- }
- return 0;
-}
-
-int
-evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
- struct timeval *tp)
-{
- ev_uint64_t abstime, usec;
- if (base->mach_timebase_units.numer == 0) {
- if (evutil_gettimeofday(tp, NULL) < 0)
- return -1;
- adjust_monotonic_time(base, tp);
- return 0;
- }
-
- abstime = mach_absolute_time();
- usec = (abstime * base->mach_timebase_units.numer)
- / (base->mach_timebase_units.denom);
- tp->tv_sec = usec / 1000000;
- tp->tv_usec = usec % 1000000;
-
- return 0;
-}
-#endif
-
-#if defined(HAVE_WIN32_MONOTONIC)
-/* =====
- Turn we now to Windows. Want monontonic time on Windows?
-
- Windows has QueryPerformanceCounter(), which gives time most high-
- resolution time. It's a pity it's not so monotonic in practice; it's
- also got some fun bugs, especially: with older Windowses, under
- virtualizations, with funny hardware, on multiprocessor systems, and so
- on. PEP418 [1] has a nice roundup of the issues here.
-
- There's GetTickCount64() on Vista and later, which gives a number of 1-msec
- ticks since startup. The accuracy here might be as bad as 10-20 msec, I
- hear. There's an undocumented function (NtSetTimerResolution) that
- allegedly increases the accuracy. Good luck!
-
- There's also GetTickCount(), which is only 32 bits, but seems to be
- supported on pre-Vista versions of Windows. Apparently, you can coax
- another 14 bits out of it, giving you 2231 years before rollover.
-
- The less said about timeGetTime() the better.
-
- "We don't care. We don't have to. We're the Phone Company."
- -- Lily Tomlin, SNL
-
- Our strategy, if precise timers are turned off, is to just use the best
- GetTickCount equivalent available. If we've been asked for precise timing,
- then we mostly[2] assume that GetTickCount is monotonic, and correct
- GetPerformanceCounter to approximate it.
-
- [1] http://www.python.org/dev/peps/pep-0418
- [2] Of course, we feed the Windows stuff into adjust_monotonic_time()
- anyway, just in case it isn't.
-
- */
-/*
- Parts of our logic in the win32 timer code here are closely based on
- BitTorrent's libUTP library. That code is subject to the following
- license:
-
- Copyright (c) 2010 BitTorrent, Inc.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-static ev_uint64_t
-evutil_GetTickCount_(struct evutil_monotonic_timer *base)
-{
- if (base->GetTickCount64_fn) {
- /* Let's just use GetTickCount64 if we can. */
- return base->GetTickCount64_fn();
- } else if (base->GetTickCount_fn) {
- /* Greg Hazel assures me that this works, that BitTorrent has
- * done it for years, and this it won't turn around and
- * bite us. He says they found it on some game programmers'
- * forum some time around 2007.
- */
- ev_uint64_t v = base->GetTickCount_fn();
- return (DWORD)v | ((v >> 18) & 0xFFFFFFFF00000000);
- } else {
- /* Here's the fallback implementation. We have to use
- * GetTickCount() with its given signature, so we only get
- * 32 bits worth of milliseconds, which will roll ove every
- * 49 days or so. */
- DWORD ticks = GetTickCount();
- if (ticks < base->last_tick_count) {
- base->adjust_tick_count += ((ev_uint64_t)1) << 32;
- }
- base->last_tick_count = ticks;
- return ticks + base->adjust_tick_count;
- }
-}
-
-int
-evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int flags)
-{
- const int precise = flags & EV_MONOT_PRECISE;
- const int fallback = flags & EV_MONOT_FALLBACK;
- HANDLE h;
- memset(base, 0, sizeof(*base));
-
- h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
- if (h != NULL && !fallback) {
- base->GetTickCount64_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount64");
- base->GetTickCount_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount");
- }
-
- base->first_tick = base->last_tick_count = evutil_GetTickCount_(base);
- if (precise && !fallback) {
- LARGE_INTEGER freq;
- if (QueryPerformanceFrequency(&freq)) {
- LARGE_INTEGER counter;
- QueryPerformanceCounter(&counter);
- base->first_counter = counter.QuadPart;
- base->usec_per_count = 1.0e6 / freq.QuadPart;
- base->use_performance_counter = 1;
- }
- }
-
- return 0;
-}
-
-static inline ev_int64_t
-abs64(ev_int64_t i)
-{
- return i < 0 ? -i : i;
-}
-
-
-int
-evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
- struct timeval *tp)
-{
- ev_uint64_t ticks = evutil_GetTickCount_(base);
- if (base->use_performance_counter) {
- /* Here's a trick we took from BitTorrent's libutp, at Greg
- * Hazel's recommendation. We use QueryPerformanceCounter for
- * our high-resolution timer, but use GetTickCount*() to keep
- * it sane, and adjust_monotonic_time() to keep it monotonic.
- */
- LARGE_INTEGER counter;
- ev_int64_t counter_elapsed, counter_usec_elapsed, ticks_elapsed;
- QueryPerformanceCounter(&counter);
- counter_elapsed = (ev_int64_t)
- (counter.QuadPart - base->first_counter);
- ticks_elapsed = ticks - base->first_tick;
- /* TODO: This may upset VC6. If you need this to work with
- * VC6, please supply an appropriate patch. */
- counter_usec_elapsed = (ev_int64_t)
- (counter_elapsed * base->usec_per_count);
-
- if (abs64(ticks_elapsed*1000 - counter_usec_elapsed) > 1000000) {
- /* It appears that the QueryPerformanceCounter()
- * result is more than 1 second away from
- * GetTickCount() result. Let's adjust it to be as
- * accurate as we can; adjust_monotnonic_time() below
- * will keep it monotonic. */
- counter_usec_elapsed = ticks_elapsed * 1000;
- base->first_counter = (ev_uint64_t) (counter.QuadPart - counter_usec_elapsed / base->usec_per_count);
- }
- tp->tv_sec = (time_t) (counter_usec_elapsed / 1000000);
- tp->tv_usec = counter_usec_elapsed % 1000000;
-
- } else {
- /* We're just using GetTickCount(). */
- tp->tv_sec = (time_t) (ticks / 1000);
- tp->tv_usec = (ticks % 1000) * 1000;
- }
- adjust_monotonic_time(base, tp);
-
- return 0;
-}
-#endif
-
-#if defined(HAVE_FALLBACK_MONOTONIC)
-/* =====
- And if none of the other options work, let's just use gettimeofday(), and
- ratchet it forward so that it acts like a monotonic timer, whether it
- wants to or not.
- */
-
-int
-evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
- int precise)
-{
- memset(base, 0, sizeof(*base));
- return 0;
-}
-
-int
-evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
- struct timeval *tp)
-{
- if (evutil_gettimeofday(tp, NULL) < 0)
- return -1;
- adjust_monotonic_time(base, tp);
- return 0;
-
-}
-#endif
diff --git a/libs/libevent/src/ht-internal.h b/libs/libevent/src/ht-internal.h
deleted file mode 100644
index 50375bbaa9..0000000000
--- a/libs/libevent/src/ht-internal.h
+++ /dev/null
@@ -1,487 +0,0 @@
-/* Copyright 2002 Christopher Clark */
-/* Copyright 2005-2012 Nick Mathewson */
-/* Copyright 2009-2012 Niels Provos and Nick Mathewson */
-/* See license at end. */
-
-/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
-
-#ifndef HT_INTERNAL_H_INCLUDED_
-#define HT_INTERNAL_H_INCLUDED_
-
-#define HT_HEAD(name, type) \
- struct name { \
- /* The hash table itself. */ \
- struct type **hth_table; \
- /* How long is the hash table? */ \
- unsigned hth_table_length; \
- /* How many elements does the table contain? */ \
- unsigned hth_n_entries; \
- /* How many elements will we allow in the table before resizing it? */ \
- unsigned hth_load_limit; \
- /* Position of hth_table_length in the primes table. */ \
- int hth_prime_idx; \
- }
-
-#define HT_INITIALIZER() \
- { NULL, 0, 0, 0, -1 }
-
-#ifdef HT_NO_CACHE_HASH_VALUES
-#define HT_ENTRY(type) \
- struct { \
- struct type *hte_next; \
- }
-#else
-#define HT_ENTRY(type) \
- struct { \
- struct type *hte_next; \
- unsigned hte_hash; \
- }
-#endif
-
-#define HT_EMPTY(head) \
- ((head)->hth_n_entries == 0)
-
-/* How many elements in 'head'? */
-#define HT_SIZE(head) \
- ((head)->hth_n_entries)
-
-/* Return memory usage for a hashtable (not counting the entries themselves) */
-#define HT_MEM_USAGE(head) \
- (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
-
-#define HT_FIND(name, head, elm) name##_HT_FIND((head), (elm))
-#define HT_INSERT(name, head, elm) name##_HT_INSERT((head), (elm))
-#define HT_REPLACE(name, head, elm) name##_HT_REPLACE((head), (elm))
-#define HT_REMOVE(name, head, elm) name##_HT_REMOVE((head), (elm))
-#define HT_START(name, head) name##_HT_START(head)
-#define HT_NEXT(name, head, elm) name##_HT_NEXT((head), (elm))
-#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm))
-#define HT_CLEAR(name, head) name##_HT_CLEAR(head)
-#define HT_INIT(name, head) name##_HT_INIT(head)
-/* Helper: */
-static inline unsigned
-ht_improve_hash_(unsigned h)
-{
- /* Aim to protect against poor hash functions by adding logic here
- * - logic taken from java 1.4 hashtable source */
- h += ~(h << 9);
- h ^= ((h >> 14) | (h << 18)); /* >>> */
- h += (h << 4);
- h ^= ((h >> 10) | (h << 22)); /* >>> */
- return h;
-}
-
-#if 0
-/** Basic string hash function, from Java standard String.hashCode(). */
-static inline unsigned
-ht_string_hash_(const char *s)
-{
- unsigned h = 0;
- int m = 1;
- while (*s) {
- h += ((signed char)*s++)*m;
- m = (m<<5)-1; /* m *= 31 */
- }
- return h;
-}
-#endif
-
-/** Basic string hash function, from Python's str.__hash__() */
-static inline unsigned
-ht_string_hash_(const char *s)
-{
- unsigned h;
- const unsigned char *cp = (const unsigned char *)s;
- h = *cp << 7;
- while (*cp) {
- h = (1000003*h) ^ *cp++;
- }
- /* This conversion truncates the length of the string, but that's ok. */
- h ^= (unsigned)(cp-(const unsigned char*)s);
- return h;
-}
-
-#ifndef HT_NO_CACHE_HASH_VALUES
-#define HT_SET_HASH_(elm, field, hashfn) \
- do { (elm)->field.hte_hash = hashfn(elm); } while (0)
-#define HT_SET_HASHVAL_(elm, field, val) \
- do { (elm)->field.hte_hash = (val); } while (0)
-#define HT_ELT_HASH_(elm, field, hashfn) \
- ((elm)->field.hte_hash)
-#else
-#define HT_SET_HASH_(elm, field, hashfn) \
- ((void)0)
-#define HT_ELT_HASH_(elm, field, hashfn) \
- (hashfn(elm))
-#define HT_SET_HASHVAL_(elm, field, val) \
- ((void)0)
-#endif
-
-/* Helper: alias for the bucket containing 'elm'. */
-#define HT_BUCKET_(head, field, elm, hashfn) \
- ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn) % head->hth_table_length])
-
-#define HT_FOREACH(x, name, head) \
- for ((x) = HT_START(name, head); \
- (x) != NULL; \
- (x) = HT_NEXT(name, head, x))
-
-#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
- int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
- void name##_HT_CLEAR(struct name *ht); \
- int name##_HT_REP_IS_BAD_(const struct name *ht); \
- static inline void \
- name##_HT_INIT(struct name *head) { \
- head->hth_table_length = 0; \
- head->hth_table = NULL; \
- head->hth_n_entries = 0; \
- head->hth_load_limit = 0; \
- head->hth_prime_idx = -1; \
- } \
- /* Helper: returns a pointer to the right location in the table \
- * 'head' to find or insert the element 'elm'. */ \
- static inline struct type ** \
- name##_HT_FIND_P_(struct name *head, struct type *elm) \
- { \
- struct type **p; \
- if (!head->hth_table) \
- return NULL; \
- p = &HT_BUCKET_(head, field, elm, hashfn); \
- while (*p) { \
- if (eqfn(*p, elm)) \
- return p; \
- p = &(*p)->field.hte_next; \
- } \
- return p; \
- } \
- /* Return a pointer to the element in the table 'head' matching 'elm', \
- * or NULL if no such element exists */ \
- static inline struct type * \
- name##_HT_FIND(const struct name *head, struct type *elm) \
- { \
- struct type **p; \
- struct name *h = (struct name *) head; \
- HT_SET_HASH_(elm, field, hashfn); \
- p = name##_HT_FIND_P_(h, elm); \
- return p ? *p : NULL; \
- } \
- /* Insert the element 'elm' into the table 'head'. Do not call this \
- * function if the table might already contain a matching element. */ \
- static inline void \
- name##_HT_INSERT(struct name *head, struct type *elm) \
- { \
- struct type **p; \
- if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
- name##_HT_GROW(head, head->hth_n_entries+1); \
- ++head->hth_n_entries; \
- HT_SET_HASH_(elm, field, hashfn); \
- p = &HT_BUCKET_(head, field, elm, hashfn); \
- elm->field.hte_next = *p; \
- *p = elm; \
- } \
- /* Insert the element 'elm' into the table 'head'. If there already \
- * a matching element in the table, replace that element and return \
- * it. */ \
- static inline struct type * \
- name##_HT_REPLACE(struct name *head, struct type *elm) \
- { \
- struct type **p, *r; \
- if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
- name##_HT_GROW(head, head->hth_n_entries+1); \
- HT_SET_HASH_(elm, field, hashfn); \
- p = name##_HT_FIND_P_(head, elm); \
- r = *p; \
- *p = elm; \
- if (r && (r!=elm)) { \
- elm->field.hte_next = r->field.hte_next; \
- r->field.hte_next = NULL; \
- return r; \
- } else { \
- ++head->hth_n_entries; \
- return NULL; \
- } \
- } \
- /* Remove any element matching 'elm' from the table 'head'. If such \
- * an element is found, return it; otherwise return NULL. */ \
- static inline struct type * \
- name##_HT_REMOVE(struct name *head, struct type *elm) \
- { \
- struct type **p, *r; \
- HT_SET_HASH_(elm, field, hashfn); \
- p = name##_HT_FIND_P_(head,elm); \
- if (!p || !*p) \
- return NULL; \
- r = *p; \
- *p = r->field.hte_next; \
- r->field.hte_next = NULL; \
- --head->hth_n_entries; \
- return r; \
- } \
- /* Invoke the function 'fn' on every element of the table 'head', \
- * using 'data' as its second argument. If the function returns \
- * nonzero, remove the most recently examined element before invoking \
- * the function again. */ \
- static inline void \
- name##_HT_FOREACH_FN(struct name *head, \
- int (*fn)(struct type *, void *), \
- void *data) \
- { \
- unsigned idx; \
- struct type **p, **nextp, *next; \
- if (!head->hth_table) \
- return; \
- for (idx=0; idx < head->hth_table_length; ++idx) { \
- p = &head->hth_table[idx]; \
- while (*p) { \
- nextp = &(*p)->field.hte_next; \
- next = *nextp; \
- if (fn(*p, data)) { \
- --head->hth_n_entries; \
- *p = next; \
- } else { \
- p = nextp; \
- } \
- } \
- } \
- } \
- /* Return a pointer to the first element in the table 'head', under \
- * an arbitrary order. This order is stable under remove operations, \
- * but not under others. If the table is empty, return NULL. */ \
- static inline struct type ** \
- name##_HT_START(struct name *head) \
- { \
- unsigned b = 0; \
- while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
- return &head->hth_table[b]; \
- ++b; \
- } \
- return NULL; \
- } \
- /* Return the next element in 'head' after 'elm', under the arbitrary \
- * order used by HT_START. If there are no more elements, return \
- * NULL. If 'elm' is to be removed from the table, you must call \
- * this function for the next value before you remove it. \
- */ \
- static inline struct type ** \
- name##_HT_NEXT(struct name *head, struct type **elm) \
- { \
- if ((*elm)->field.hte_next) { \
- return &(*elm)->field.hte_next; \
- } else { \
- unsigned b = (HT_ELT_HASH_(*elm, field, hashfn) % head->hth_table_length)+1; \
- while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
- return &head->hth_table[b]; \
- ++b; \
- } \
- return NULL; \
- } \
- } \
- static inline struct type ** \
- name##_HT_NEXT_RMV(struct name *head, struct type **elm) \
- { \
- unsigned h = HT_ELT_HASH_(*elm, field, hashfn); \
- *elm = (*elm)->field.hte_next; \
- --head->hth_n_entries; \
- if (*elm) { \
- return elm; \
- } else { \
- unsigned b = (h % head->hth_table_length)+1; \
- while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
- return &head->hth_table[b]; \
- ++b; \
- } \
- return NULL; \
- } \
- }
-
-#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
- reallocfn, freefn) \
- static unsigned name##_PRIMES[] = { \
- 53, 97, 193, 389, \
- 769, 1543, 3079, 6151, \
- 12289, 24593, 49157, 98317, \
- 196613, 393241, 786433, 1572869, \
- 3145739, 6291469, 12582917, 25165843, \
- 50331653, 100663319, 201326611, 402653189, \
- 805306457, 1610612741 \
- }; \
- static unsigned name##_N_PRIMES = \
- (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0])); \
- /* Expand the internal table of 'head' until it is large enough to \
- * hold 'size' elements. Return 0 on success, -1 on allocation \
- * failure. */ \
- int \
- name##_HT_GROW(struct name *head, unsigned size) \
- { \
- unsigned new_len, new_load_limit; \
- int prime_idx; \
- struct type **new_table; \
- if (head->hth_prime_idx == (int)name##_N_PRIMES - 1) \
- return 0; \
- if (head->hth_load_limit > size) \
- return 0; \
- prime_idx = head->hth_prime_idx; \
- do { \
- new_len = name##_PRIMES[++prime_idx]; \
- new_load_limit = (unsigned)(load*new_len); \
- } while (new_load_limit <= size && \
- prime_idx < (int)name##_N_PRIMES); \
- if ((new_table = mallocfn(new_len*sizeof(struct type*)))) { \
- unsigned b; \
- memset(new_table, 0, new_len*sizeof(struct type*)); \
- for (b = 0; b < head->hth_table_length; ++b) { \
- struct type *elm, *next; \
- unsigned b2; \
- elm = head->hth_table[b]; \
- while (elm) { \
- next = elm->field.hte_next; \
- b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len; \
- elm->field.hte_next = new_table[b2]; \
- new_table[b2] = elm; \
- elm = next; \
- } \
- } \
- if (head->hth_table) \
- freefn(head->hth_table); \
- head->hth_table = new_table; \
- } else { \
- unsigned b, b2; \
- new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \
- if (!new_table) return -1; \
- memset(new_table + head->hth_table_length, 0, \
- (new_len - head->hth_table_length)*sizeof(struct type*)); \
- for (b=0; b < head->hth_table_length; ++b) { \
- struct type *e, **pE; \
- for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) { \
- b2 = HT_ELT_HASH_(e, field, hashfn) % new_len; \
- if (b2 == b) { \
- pE = &e->field.hte_next; \
- } else { \
- *pE = e->field.hte_next; \
- e->field.hte_next = new_table[b2]; \
- new_table[b2] = e; \
- } \
- } \
- } \
- head->hth_table = new_table; \
- } \
- head->hth_table_length = new_len; \
- head->hth_prime_idx = prime_idx; \
- head->hth_load_limit = new_load_limit; \
- return 0; \
- } \
- /* Free all storage held by 'head'. Does not free 'head' itself, or \
- * individual elements. */ \
- void \
- name##_HT_CLEAR(struct name *head) \
- { \
- if (head->hth_table) \
- freefn(head->hth_table); \
- name##_HT_INIT(head); \
- } \
- /* Debugging helper: return false iff the representation of 'head' is \
- * internally consistent. */ \
- int \
- name##_HT_REP_IS_BAD_(const struct name *head) \
- { \
- unsigned n, i; \
- struct type *elm; \
- if (!head->hth_table_length) { \
- if (!head->hth_table && !head->hth_n_entries && \
- !head->hth_load_limit && head->hth_prime_idx == -1) \
- return 0; \
- else \
- return 1; \
- } \
- if (!head->hth_table || head->hth_prime_idx < 0 || \
- !head->hth_load_limit) \
- return 2; \
- if (head->hth_n_entries > head->hth_load_limit) \
- return 3; \
- if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx]) \
- return 4; \
- if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \
- return 5; \
- for (n = i = 0; i < head->hth_table_length; ++i) { \
- for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \
- if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \
- return 1000 + i; \
- if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
- return 10000 + i; \
- ++n; \
- } \
- } \
- if (n != head->hth_n_entries) \
- return 6; \
- return 0; \
- }
-
-/** Implements an over-optimized "find and insert if absent" block;
- * not meant for direct usage by typical code, or usage outside the critical
- * path.*/
-#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
- { \
- struct name *var##_head_ = head; \
- struct eltype **var; \
- if (!var##_head_->hth_table || \
- var##_head_->hth_n_entries >= var##_head_->hth_load_limit) \
- name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1); \
- HT_SET_HASH_((elm), field, hashfn); \
- var = name##_HT_FIND_P_(var##_head_, (elm)); \
- if (*var) { \
- y; \
- } else { \
- n; \
- } \
- }
-#define HT_FOI_INSERT_(field, head, elm, newent, var) \
- { \
- HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash); \
- newent->field.hte_next = NULL; \
- *var = newent; \
- ++((head)->hth_n_entries); \
- }
-
-/*
- * Copyright 2005, Nick Mathewson. Implementation logic is adapted from code
- * by Christopher Clark, retrofit to allow drop-in memory management, and to
- * use the same interface as Niels Provos's tree.h. This is probably still
- * a derived work, so the original license below still applies.
- *
- * Copyright (c) 2002, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * 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.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
- * 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.
-*/
-
-#endif
-
diff --git a/libs/libevent/src/http-internal.h b/libs/libevent/src/http-internal.h
deleted file mode 100644
index ba6e49ef9b..0000000000
--- a/libs/libevent/src/http-internal.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright 2001-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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_INTERNAL_H_INCLUDED_
-#define HTTP_INTERNAL_H_INCLUDED_
-
-#include "event2/event_struct.h"
-#include "util-internal.h"
-#include "defer-internal.h"
-
-#define HTTP_CONNECT_TIMEOUT 45
-#define HTTP_WRITE_TIMEOUT 50
-#define HTTP_READ_TIMEOUT 50
-
-#define HTTP_PREFIX "http://"
-#define HTTP_DEFAULTPORT 80
-
-enum message_read_status {
- ALL_DATA_READ = 1,
- MORE_DATA_EXPECTED = 0,
- DATA_CORRUPTED = -1,
- REQUEST_CANCELED = -2,
- DATA_TOO_LONG = -3
-};
-
-struct evbuffer;
-struct addrinfo;
-struct evhttp_request;
-
-/* Indicates an unknown request method. */
-#define EVHTTP_REQ_UNKNOWN_ (1<<15)
-
-enum evhttp_connection_state {
- EVCON_DISCONNECTED, /**< not currently connected not trying either*/
- EVCON_CONNECTING, /**< tries to currently connect */
- EVCON_IDLE, /**< connection is established */
- EVCON_READING_FIRSTLINE,/**< reading Request-Line (incoming conn) or
- **< Status-Line (outgoing conn) */
- EVCON_READING_HEADERS, /**< reading request/response headers */
- EVCON_READING_BODY, /**< reading request/response body */
- EVCON_READING_TRAILER, /**< reading request/response chunked trailer */
- EVCON_WRITING /**< writing request/response headers/body */
-};
-
-struct event_base;
-
-/* A client or server connection. */
-struct evhttp_connection {
- /* we use this tailq only if this connection was created for an http
- * server */
- TAILQ_ENTRY(evhttp_connection) next;
-
- evutil_socket_t fd;
- struct bufferevent *bufev;
-
- struct event retry_ev; /* for retrying connects */
-
- char *bind_address; /* address to use for binding the src */
- unsigned short bind_port; /* local port for binding the src */
-
- char *address; /* address to connect to */
- unsigned short port;
-
- size_t max_headers_size;
- ev_uint64_t max_body_size;
-
- 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 */
-/* set when we want to auto free the connection */
-#define EVHTTP_CON_AUTOFREE EVHTTP_CON_PUBLIC_FLAGS_END
-
- struct timeval timeout; /* timeout for events */
- int retry_cnt; /* retry count */
- int retry_max; /* maximum number of retries */
- struct timeval initial_retry_timeout; /* Timeout for low long to wait
- * after first failing attempt
- * before retry */
-
- 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_callback read_more_deferred_cb;
-
- struct event_base *base;
- struct evdns_base *dns_base;
- int ai_family;
-};
-
-/* A callback for an http server */
-struct evhttp_cb {
- TAILQ_ENTRY(evhttp_cb) next;
-
- char *what;
-
- void (*cb)(struct evhttp_request *req, void *);
- void *cbarg;
-};
-
-/* both the http server as well as the rpc system need to queue connections */
-TAILQ_HEAD(evconq, evhttp_connection);
-
-/* each bound socket is stored in one of these */
-struct evhttp_bound_socket {
- TAILQ_ENTRY(evhttp_bound_socket) next;
-
- struct evconnlistener *listener;
-};
-
-/* server alias list item. */
-struct evhttp_server_alias {
- TAILQ_ENTRY(evhttp_server_alias) next;
-
- char *alias; /* the server alias. */
-};
-
-struct evhttp {
- /* Next vhost, if this is a vhost. */
- TAILQ_ENTRY(evhttp) next_vhost;
-
- /* All listeners for this host */
- TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
-
- TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
-
- /* All live connections on this host. */
- struct evconq connections;
-
- TAILQ_HEAD(vhostsq, evhttp) virtualhosts;
-
- TAILQ_HEAD(aliasq, evhttp_server_alias) aliases;
-
- /* NULL if this server is not a vhost */
- char *vhost_pattern;
-
- struct timeval timeout;
-
- size_t default_max_headers_size;
- ev_uint64_t default_max_body_size;
- const char *default_content_type;
-
- /* Bitmask of all HTTP methods that we accept and pass to user
- * callbacks. */
- ev_uint16_t allowed_methods;
-
- /* Fallback callback if all the other callbacks for this connection
- don't match. */
- void (*gencb)(struct evhttp_request *req, void *);
- void *gencbarg;
- struct bufferevent* (*bevcb)(struct event_base *, void *);
- void *bevcbarg;
-
- struct event_base *base;
-};
-
-/* XXX most of these functions could be static. */
-
-/* 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 *);
-
-enum evhttp_request_error;
-/* notifies the current request that it failed; resets connection */
-void evhttp_connection_fail_(struct evhttp_connection *,
- enum evhttp_request_error error);
-
-enum message_read_status;
-
-enum message_read_status evhttp_parse_firstline_(struct evhttp_request *, struct evbuffer*);
-enum message_read_status evhttp_parse_headers_(struct evhttp_request *, struct evbuffer*);
-
-void evhttp_start_read_(struct evhttp_connection *);
-
-/* 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 *);
-
-int evhttp_decode_uri_internal(const char *uri, size_t length,
- char *ret, int decode_plus);
-
-#endif /* _HTTP_H */
diff --git a/libs/libevent/src/http.c b/libs/libevent/src/http.c
deleted file mode 100644
index fd7ce3cbf2..0000000000
--- a/libs/libevent/src/http.c
+++ /dev/null
@@ -1,4892 +0,0 @@
-/*
- * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef EVENT__HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef EVENT__HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_IOCCOM_H
-#include <sys/ioccom.h>
-#endif
-#ifdef EVENT__HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
-#endif
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef EVENT__HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#ifndef _WIN32
-#include <sys/socket.h>
-#include <sys/stat.h>
-#else
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-
-#include <sys/queue.h>
-
-#ifdef EVENT__HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef EVENT__HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef EVENT__HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
-#ifdef _WIN32
-#include <winsock2.h>
-#endif
-
-#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 EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef EVENT__HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#undef timeout_pending
-#undef timeout_initialized
-
-#include "strlcpy-internal.h"
-#include "event2/http.h"
-#include "event2/event.h"
-#include "event2/buffer.h"
-#include "event2/bufferevent.h"
-#include "event2/http_struct.h"
-#include "event2/http_compat.h"
-#include "event2/util.h"
-#include "event2/listener.h"
-#include "log-internal.h"
-#include "util-internal.h"
-#include "http-internal.h"
-#include "mm-internal.h"
-#include "bufferevent-internal.h"
-
-#ifndef EVENT__HAVE_GETNAMEINFO
-#define NI_MAXSERV 32
-#define NI_MAXHOST 1025
-
-#ifndef NI_NUMERICHOST
-#define NI_NUMERICHOST 1
-#endif
-
-#ifndef NI_NUMERICSERV
-#define NI_NUMERICSERV 2
-#endif
-
-static int
-fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
- size_t hostlen, char *serv, size_t servlen, int flags)
-{
- struct sockaddr_in *sin = (struct sockaddr_in *)sa;
-
- if (serv != NULL) {
- char tmpserv[16];
- evutil_snprintf(tmpserv, sizeof(tmpserv),
- "%d", ntohs(sin->sin_port));
- if (strlcpy(serv, tmpserv, servlen) >= servlen)
- return (-1);
- }
-
- if (host != NULL) {
- if (flags & NI_NUMERICHOST) {
- if (strlcpy(host, inet_ntoa(sin->sin_addr),
- hostlen) >= hostlen)
- return (-1);
- else
- return (0);
- } else {
- struct hostent *hp;
- hp = gethostbyaddr((char *)&sin->sin_addr,
- sizeof(struct in_addr), AF_INET);
- if (hp == NULL)
- return (-2);
-
- if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
- return (-1);
- else
- return (0);
- }
- }
- return (0);
-}
-
-#endif
-
-#define REQ_VERSION_BEFORE(req, major_v, minor_v) \
- ((req)->major < (major_v) || \
- ((req)->major == (major_v) && (req)->minor < (minor_v)))
-
-#define REQ_VERSION_ATLEAST(req, major_v, minor_v) \
- ((req)->major > (major_v) || \
- ((req)->major == (major_v) && (req)->minor >= (minor_v)))
-
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-extern int debug;
-
-static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse);
-static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
-static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
-static int evhttp_associate_new_request_with_connection(
- struct evhttp_connection *evcon);
-static void evhttp_connection_start_detectclose(
- struct evhttp_connection *evcon);
-static void evhttp_connection_stop_detectclose(
- struct evhttp_connection *evcon);
-static void evhttp_request_dispatch(struct evhttp_connection* evcon);
-static void evhttp_read_firstline(struct evhttp_connection *evcon,
- struct evhttp_request *req);
-static void evhttp_read_header(struct evhttp_connection *evcon,
- struct evhttp_request *req);
-static int evhttp_add_header_internal(struct evkeyvalq *headers,
- const char *key, const char *value);
-static const char *evhttp_response_phrase_internal(int code);
-static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
-static void evhttp_write_buffer(struct evhttp_connection *,
- void (*)(struct evhttp_connection *, void *), void *);
-static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
-
-/* callbacks for bufferevent */
-static void evhttp_read_cb(struct bufferevent *, void *);
-static void evhttp_write_cb(struct bufferevent *, void *);
-static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg);
-static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
- const char *hostname);
-
-#ifndef EVENT__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;
- EVUTIL_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 size_t
-html_replace(const char ch, const char **escaped)
-{
- switch (ch) {
- case '<':
- *escaped = "&lt;";
- return 4;
- case '>':
- *escaped = "&gt;";
- return 4;
- case '"':
- *escaped = "&quot;";
- return 6;
- case '\'':
- *escaped = "&#039;";
- return 6;
- case '&':
- *escaped = "&amp;";
- return 5;
- default:
- break;
- }
-
- return 1;
-}
-
-/*
- * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
- * &#039; and &amp; correspondingly.
- *
- * The returned string needs to be freed by the caller.
- */
-
-char *
-evhttp_htmlescape(const char *html)
-{
- size_t i;
- size_t new_size = 0, old_size = 0;
- char *escaped_html, *p;
-
- if (html == NULL)
- return (NULL);
-
- old_size = strlen(html);
- for (i = 0; i < old_size; ++i) {
- const char *replaced = NULL;
- const size_t replace_size = html_replace(html[i], &replaced);
- if (replace_size > EV_SIZE_MAX - new_size) {
- event_warn("%s: html_replace overflow", __func__);
- return (NULL);
- }
- new_size += replace_size;
- }
-
- if (new_size == EV_SIZE_MAX)
- return (NULL);
- p = escaped_html = mm_malloc(new_size + 1);
- if (escaped_html == NULL) {
- event_warn("%s: malloc(%lu)", __func__,
- (unsigned long)(new_size + 1));
- return (NULL);
- }
- for (i = 0; i < old_size; ++i) {
- const char *replaced = &html[i];
- const size_t len = html_replace(html[i], &replaced);
- memcpy(p, replaced, len);
- p += len;
- }
-
- *p = '\0';
-
- return (escaped_html);
-}
-
-/** Given an evhttp_cmd_type, returns a constant string containing the
- * equivalent HTTP command, or NULL if the evhttp_command_type is
- * unrecognized. */
-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;
- case EVHTTP_REQ_PUT:
- method = "PUT";
- break;
- case EVHTTP_REQ_DELETE:
- method = "DELETE";
- break;
- case EVHTTP_REQ_OPTIONS:
- method = "OPTIONS";
- break;
- case EVHTTP_REQ_TRACE:
- method = "TRACE";
- break;
- case EVHTTP_REQ_CONNECT:
- method = "CONNECT";
- break;
- case EVHTTP_REQ_PATCH:
- method = "PATCH";
- break;
- default:
- method = NULL;
- break;
- }
-
- return (method);
-}
-
-/**
- * Determines if a response should have a body.
- * Follows the rules in RFC 2616 section 4.3.
- * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
- * a body.
- */
-static int
-evhttp_response_needs_body(struct evhttp_request *req)
-{
- return (req->response_code != HTTP_NOCONTENT &&
- req->response_code != HTTP_NOTMODIFIED &&
- (req->response_code < 100 || req->response_code >= 200) &&
- req->type != EVHTTP_REQ_HEAD);
-}
-
-/** Helper: called after we've added some data to an evcon's bufferevent's
- * output buffer. Sets the evconn's writing-is-done callback, and puts
- * the bufferevent into writing mode.
- */
-static 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;
-
- /* Disable the read callback: we don't actually care about data;
- * we only care about close detection. (We don't disable reading,
- * since we *do* want to learn about any close events.) */
- bufferevent_setcb(evcon->bufev,
- NULL, /*read*/
- evhttp_write_cb,
- evhttp_error_cb,
- evcon);
-
- bufferevent_enable(evcon->bufev, EV_WRITE);
-}
-
-static void
-evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg)
-{
- bufferevent_disable(evcon->bufev, EV_WRITE);
-}
-
-static void
-evhttp_send_continue(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- bufferevent_enable(evcon->bufev, EV_WRITE);
- evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
- "HTTP/%d.%d 100 Continue\r\n\r\n",
- req->major, req->minor);
- evcon->cb = evhttp_send_continue_done;
- evcon->cb_arg = NULL;
- bufferevent_setcb(evcon->bufev,
- evhttp_read_cb,
- evhttp_write_cb,
- evhttp_error_cb,
- evcon);
-}
-
-/** Helper: returns true iff evconn is in any connected state. */
-static int
-evhttp_connected(struct evhttp_connection *evcon)
-{
- switch (evcon->state) {
- case EVCON_DISCONNECTED:
- case EVCON_CONNECTING:
- return (0);
- case EVCON_IDLE:
- case EVCON_READING_FIRSTLINE:
- case EVCON_READING_HEADERS:
- case EVCON_READING_BODY:
- case EVCON_READING_TRAILER:
- case EVCON_WRITING:
- default:
- return (1);
- }
-}
-
-/* Create the headers needed for an outgoing HTTP request, adds them to
- * the request's header list, and writes the request line to the
- * connection's output buffer.
- */
-static void
-evhttp_make_header_request(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- const char *method;
-
- evhttp_remove_header(req->output_headers, "Proxy-Connection");
-
- /* Generate request line */
- method = evhttp_method(req->type);
- evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
- "%s %s HTTP/%d.%d\r\n",
- method, req->uri, req->major, req->minor);
-
- /* Add the content length on a post or put request if missing */
- if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
- evhttp_find_header(req->output_headers, "Content-Length") == NULL){
- char size[22];
- evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
- EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
- evhttp_add_header(req->output_headers, "Content-Length", size);
- }
-}
-
-/** Return true if the list of headers in 'headers', intepreted with respect
- * to flags, means that we should send a "connection: close" when the request
- * is done. */
-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 || evutil_ascii_strcasecmp(connection, "keep-alive") != 0);
- } else {
- const char *connection = evhttp_find_header(headers, "Connection");
- return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
- }
-}
-static int
-evhttp_is_request_connection_close(struct evhttp_request *req)
-{
- return
- evhttp_is_connection_close(req->flags, req->input_headers) ||
- evhttp_is_connection_close(req->flags, req->output_headers);
-}
-
-/* Return true iff 'headers' contains 'Connection: keep-alive' */
-static int
-evhttp_is_connection_keepalive(struct evkeyvalq* headers)
-{
- const char *connection = evhttp_find_header(headers, "Connection");
- return (connection != NULL
- && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
-}
-
-/* Add a correct "Date" header to headers, unless it already has one. */
-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);
- }
- }
-}
-
-/* Add a "Content-Length" header with value 'content_length' to headers,
- * unless it already has a content-length or transfer-encoding header. */
-static void
-evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
- size_t content_length)
-{
- if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
- evhttp_find_header(headers, "Content-Length") == NULL) {
- char len[22];
- evutil_snprintf(len, sizeof(len), EV_SIZE_FMT,
- EV_SIZE_ARG(content_length));
- evhttp_add_header(headers, "Content-Length", len);
- }
-}
-
-/*
- * Create the headers needed for an HTTP reply in req->output_headers,
- * and write the first HTTP response for req line to evcon.
- */
-static void
-evhttp_make_header_response(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
- evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
- "HTTP/%d.%d %d %s\r\n",
- req->major, req->minor, req->response_code,
- req->response_code_line);
-
- if (req->major == 1) {
- if (req->minor >= 1)
- evhttp_maybe_add_date_header(req->output_headers);
-
- /*
- * if the protocol is 1.0; and the connection was keep-alive
- * we need to add a keep-alive header, too.
- */
- if (req->minor == 0 && is_keepalive)
- evhttp_add_header(req->output_headers,
- "Connection", "keep-alive");
-
- if ((req->minor >= 1 || is_keepalive) &&
- evhttp_response_needs_body(req)) {
- /*
- * 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,
- evbuffer_get_length(req->output_buffer));
- }
- }
-
- /* Potentially add headers for unidentified content. */
- if (evhttp_response_needs_body(req)) {
- if (evhttp_find_header(req->output_headers,
- "Content-Type") == NULL
- && evcon->http_server->default_content_type) {
- evhttp_add_header(req->output_headers,
- "Content-Type",
- evcon->http_server->default_content_type);
- }
- }
-
- /* 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");
- }
-}
-
-/** Generate all headers appropriate for sending the http request in req (or
- * the response, if we're sending a response), and write them to evcon's
- * bufferevent. Also writes all data from req->output_buffer */
-static void
-evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- struct evkeyval *header;
- struct evbuffer *output = bufferevent_get_output(evcon->bufev);
-
- /*
- * Depending if this is a HTTP request or response, we might need to
- * add some new headers or remove existing headers.
- */
- if (req->kind == EVHTTP_REQUEST) {
- evhttp_make_header_request(evcon, req);
- } else {
- evhttp_make_header_response(evcon, req);
- }
-
- TAILQ_FOREACH(header, req->output_headers, next) {
- evbuffer_add_printf(output, "%s: %s\r\n",
- header->key, header->value);
- }
- evbuffer_add(output, "\r\n", 2);
-
- if (evbuffer_get_length(req->output_buffer) > 0) {
- /*
- * For a request, we add the POST data, for a reply, this
- * is the regular data.
- */
- /* XXX We might want to support waiting (a limited amount of
- time) for a continue status line from the server before
- sending POST/PUT message bodies. */
- evbuffer_add_buffer(output, req->output_buffer);
- }
-}
-
-void
-evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
- ev_ssize_t new_max_headers_size)
-{
- if (new_max_headers_size<0)
- evcon->max_headers_size = EV_SIZE_MAX;
- else
- evcon->max_headers_size = new_max_headers_size;
-}
-void
-evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
- ev_ssize_t new_max_body_size)
-{
- if (new_max_body_size<0)
- evcon->max_body_size = EV_UINT64_MAX;
- else
- evcon->max_body_size = new_max_body_size;
-}
-
-static int
-evhttp_connection_incoming_fail(struct evhttp_request *req,
- enum evhttp_request_error error)
-{
- switch (error) {
- case EVREQ_HTTP_TIMEOUT:
- case EVREQ_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. when
- * the request is still being used for sending, we
- * need to disassociated it from the connection here.
- */
- if (!req->userdone) {
- /* remove it so that it will not be freed */
- TAILQ_REMOVE(&req->evcon->requests, req, next);
- /* indicate that this request no longer has a
- * connection object
- */
- req->evcon = NULL;
- }
- return (-1);
- case EVREQ_HTTP_INVALID_HEADER:
- case EVREQ_HTTP_BUFFER_ERROR:
- case EVREQ_HTTP_REQUEST_CANCEL:
- case EVREQ_HTTP_DATA_TOO_LONG:
- default: /* xxx: probably should just error on default */
- /* the callback looks at the uri to determine errors */
- if (req->uri) {
- mm_free(req->uri);
- req->uri = NULL;
- }
- if (req->uri_elems) {
- evhttp_uri_free(req->uri_elems);
- req->uri_elems = 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);
-}
-
-/* Free connection ownership of which can be acquired by user using
- * evhttp_request_own(). */
-static inline void
-evhttp_request_free_auto(struct evhttp_request *req)
-{
- if (!(req->flags & EVHTTP_USER_OWNED))
- evhttp_request_free(req);
-}
-
-static void
-evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- TAILQ_REMOVE(&evcon->requests, req, next);
- evhttp_request_free_auto(req);
-}
-
-/* Called when evcon has experienced a (non-recoverable? -NM) error, as
- * given in error. If it's an outgoing connection, reset the connection,
- * retry any pending requests, and inform the user. If it's incoming,
- * delegates to evhttp_connection_incoming_fail(). */
-void
-evhttp_connection_fail_(struct evhttp_connection *evcon,
- enum evhttp_request_error error)
-{
- const int errsave = EVUTIL_SOCKET_ERROR();
- struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
- void (*cb)(struct evhttp_request *, void *);
- void *cb_arg;
- void (*error_cb)(enum evhttp_request_error, void *);
- void *error_cb_arg;
- EVUTIL_ASSERT(req != NULL);
-
- bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
-
- 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;
- }
-
- error_cb = req->error_cb;
- error_cb_arg = req->cb_arg;
- /* when the request was canceled, the callback is not executed */
- if (error != EVREQ_HTTP_REQUEST_CANCEL) {
- /* save the callback for later; the cb might free our object */
- cb = req->cb;
- cb_arg = req->cb_arg;
- } else {
- cb = NULL;
- cb_arg = NULL;
- }
-
- /* do not fail all requests; the next request is going to get
- * send over a new connection. when a user cancels a request,
- * all other pending requests should be processed as normal
- */
- evhttp_request_free_(evcon, req);
-
- /* 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);
-
- /* The call to evhttp_connection_reset_ overwrote errno.
- * Let's restore the original errno, so that the user's
- * callback can have a better idea of what the error was.
- */
- EVUTIL_SET_SOCKET_ERROR(errsave);
-
- /* inform the user */
- if (error_cb != NULL)
- error_cb(error, error_cb_arg);
- if (cb != NULL)
- (*cb)(NULL, cb_arg);
-}
-
-/* Bufferevent callback: invoked when any data has been written from an
- * http connection's bufferevent */
-static void
-evhttp_write_cb(struct bufferevent *bufev, void *arg)
-{
- struct evhttp_connection *evcon = arg;
-
- /* Activate our call back */
- if (evcon->cb != NULL)
- (*evcon->cb)(evcon, evcon->cb_arg);
-}
-
-/**
- * Advance the connection state.
- * - If this is an outgoing connection, we've just processed the response;
- * idle or close the connection.
- * - If this is an incoming connection, we've just processed the request;
- * respond.
- */
-static void
-evhttp_connection_done(struct evhttp_connection *evcon)
-{
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
- int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
- int free_evcon = 0;
-
- if (con_outgoing) {
- /* idle or close the connection */
- int need_close = evhttp_is_request_connection_close(req);
- TAILQ_REMOVE(&evcon->requests, req, next);
- req->evcon = NULL;
-
- evcon->state = EVCON_IDLE;
-
- /* check if we got asked to close the connection */
- if (need_close)
- evhttp_connection_reset_(evcon);
-
- if (TAILQ_FIRST(&evcon->requests) != NULL) {
- /*
- * We have more requests; reset the connection
- * and deal with the next request.
- */
- if (!evhttp_connected(evcon))
- evhttp_connection_connect_(evcon);
- else
- evhttp_request_dispatch(evcon);
- } else if (!need_close) {
- /*
- * The connection is going to be persistent, but we
- * need to detect if the other side closes it.
- */
- evhttp_connection_start_detectclose(evcon);
- } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
- /*
- * If we have no more requests that need completion
- * and we're not waiting for the connection to close
- */
- free_evcon = 1;
- }
- } else {
- /*
- * incoming connection - we need to leave the request on the
- * connection so that we can reply to it.
- */
- evcon->state = EVCON_WRITING;
- }
-
- /* notify the user of the request */
- (*req->cb)(req, req->cb_arg);
-
- /* if this was an outgoing request, we own and it's done. so free it. */
- if (con_outgoing) {
- evhttp_request_free_auto(req);
- }
-
- /* If this was the last request of an outgoing connection and we're
- * not waiting to receive a connection close event and we want to
- * automatically free the connection. We check to ensure our request
- * list is empty one last time just in case our callback added a
- * new request.
- */
- if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
- evhttp_connection_free(evcon);
- }
-}
-
-/*
- * Handles reading from a chunked request.
- * return ALL_DATA_READ:
- * all data has been read
- * return MORE_DATA_EXPECTED:
- * more data is expected
- * return DATA_CORRUPTED:
- * data is corrupted
- * return REQUEST_CANCELED:
- * request was canceled by the user calling evhttp_cancel_request
- * return DATA_TOO_LONG:
- * ran over the maximum limit
- */
-
-static enum message_read_status
-evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
-{
- if (req == NULL || buf == NULL) {
- return DATA_CORRUPTED;
- }
-
- while (1) {
- size_t buflen;
-
- if ((buflen = evbuffer_get_length(buf)) == 0) {
- break;
- }
-
- /* evbuffer_get_length returns size_t, but len variable is ssize_t,
- * check for overflow conditions */
- if (buflen > EV_SSIZE_MAX) {
- return DATA_CORRUPTED;
- }
-
- if (req->ntoread < 0) {
- /* Read chunk size */
- ev_int64_t ntoread;
- char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF);
- char *endp;
- int error;
- if (p == NULL)
- break;
- /* the last chunk is on a new line? */
- if (strlen(p) == 0) {
- mm_free(p);
- continue;
- }
- ntoread = evutil_strtoll(p, &endp, 16);
- error = (*p == '\0' ||
- (*endp != '\0' && *endp != ' ') ||
- ntoread < 0);
- mm_free(p);
- if (error) {
- /* could not get chunk size */
- return (DATA_CORRUPTED);
- }
-
- /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
- if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) {
- return DATA_CORRUPTED;
- }
-
- if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
- /* failed body length test */
- event_debug(("Request body is too long"));
- return (DATA_TOO_LONG);
- }
-
- req->body_size += (size_t)ntoread;
- req->ntoread = ntoread;
- if (req->ntoread == 0) {
- /* Last chunk */
- return (ALL_DATA_READ);
- }
- continue;
- }
-
- /* req->ntoread is signed int64, len is ssize_t, based on arch,
- * ssize_t could only be 32b, check for these conditions */
- if (req->ntoread > EV_SSIZE_MAX) {
- return DATA_CORRUPTED;
- }
-
- /* don't have enough to complete a chunk; wait for more */
- if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread)
- return (MORE_DATA_EXPECTED);
-
- /* Completed chunk */
- evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
- req->ntoread = -1;
- if (req->chunk_cb != NULL) {
- req->flags |= EVHTTP_REQ_DEFER_FREE;
- (*req->chunk_cb)(req, req->cb_arg);
- evbuffer_drain(req->input_buffer,
- evbuffer_get_length(req->input_buffer));
- req->flags &= ~EVHTTP_REQ_DEFER_FREE;
- if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
- return (REQUEST_CANCELED);
- }
- }
- }
-
- return (MORE_DATA_EXPECTED);
-}
-
-static void
-evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
-
- switch (evhttp_parse_headers_(req, buf)) {
- case DATA_CORRUPTED:
- case DATA_TOO_LONG:
- evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
- break;
- case ALL_DATA_READ:
- bufferevent_disable(evcon->bufev, EV_READ);
- evhttp_connection_done(evcon);
- break;
- case MORE_DATA_EXPECTED:
- case REQUEST_CANCELED: /* ??? */
- default:
- break;
- }
-}
-
-static void
-evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
-{
- struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
-
- if (req->chunked) {
- switch (evhttp_handle_chunked_read(req, buf)) {
- case ALL_DATA_READ:
- /* finished last chunk */
- evcon->state = EVCON_READING_TRAILER;
- evhttp_read_trailer(evcon, req);
- return;
- case DATA_CORRUPTED:
- case DATA_TOO_LONG:
- /* corrupted data */
- evhttp_connection_fail_(evcon,
- EVREQ_HTTP_DATA_TOO_LONG);
- return;
- case REQUEST_CANCELED:
- /* request canceled */
- evhttp_request_free_auto(req);
- return;
- case MORE_DATA_EXPECTED:
- default:
- break;
- }
- } else if (req->ntoread < 0) {
- /* Read until connection close. */
- if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
- evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
- return;
- }
-
- req->body_size += evbuffer_get_length(buf);
- evbuffer_add_buffer(req->input_buffer, buf);
- } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
- /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
- /* We've postponed moving the data until now, but we're
- * about to use it. */
- size_t n = evbuffer_get_length(buf);
-
- if (n > (size_t) req->ntoread)
- n = (size_t) req->ntoread;
- req->ntoread -= n;
- req->body_size += n;
- evbuffer_remove_buffer(buf, req->input_buffer, n);
- }
-
- if (req->body_size > req->evcon->max_body_size ||
- (!req->chunked && req->ntoread >= 0 &&
- (size_t)req->ntoread > req->evcon->max_body_size)) {
- /* XXX: The above casted comparison must checked for overflow */
- /* failed body length test */
- event_debug(("Request body is too long"));
- evhttp_connection_fail_(evcon,
- EVREQ_HTTP_DATA_TOO_LONG);
- return;
- }
-
- if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) {
- req->flags |= EVHTTP_REQ_DEFER_FREE;
- (*req->chunk_cb)(req, req->cb_arg);
- req->flags &= ~EVHTTP_REQ_DEFER_FREE;
- evbuffer_drain(req->input_buffer,
- evbuffer_get_length(req->input_buffer));
- if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
- evhttp_request_free_auto(req);
- return;
- }
- }
-
- if (req->ntoread == 0) {
- bufferevent_disable(evcon->bufev, EV_READ);
- /* Completed content length */
- evhttp_connection_done(evcon);
- return;
- }
-}
-
-#define get_deferred_queue(evcon) \
- ((evcon)->base)
-
-/*
- * Gets called when more data becomes available
- */
-
-static void
-evhttp_read_cb(struct bufferevent *bufev, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
-
- /* Cancel if it's pending. */
- event_deferred_cb_cancel_(get_deferred_queue(evcon),
- &evcon->read_more_deferred_cb);
-
- switch (evcon->state) {
- case EVCON_READING_FIRSTLINE:
- evhttp_read_firstline(evcon, req);
- /* note the request may have been freed in
- * evhttp_read_body */
- break;
- case EVCON_READING_HEADERS:
- evhttp_read_header(evcon, req);
- /* note the request may have been freed in
- * evhttp_read_body */
- break;
- case EVCON_READING_BODY:
- evhttp_read_body(evcon, req);
- /* note the request may have been freed in
- * evhttp_read_body */
- break;
- case EVCON_READING_TRAILER:
- evhttp_read_trailer(evcon, req);
- break;
- case EVCON_IDLE:
- {
-#ifdef USE_DEBUG
- struct evbuffer *input;
- size_t total_len;
-
- input = bufferevent_get_input(evcon->bufev);
- total_len = evbuffer_get_length(input);
- event_debug(("%s: read "EV_SIZE_FMT
- " bytes in EVCON_IDLE state,"
- " resetting connection",
- __func__, EV_SIZE_ARG(total_len)));
-#endif
-
- evhttp_connection_reset_(evcon);
- }
- break;
- case EVCON_DISCONNECTED:
- case EVCON_CONNECTING:
- case EVCON_WRITING:
- default:
- event_errx(1, "%s: illegal connection state %d",
- __func__, evcon->state);
- }
-}
-
-static void
-evhttp_deferred_read_cb(struct event_callback *cb, void *data)
-{
- struct evhttp_connection *evcon = data;
- evhttp_read_cb(evcon->bufev, evcon);
-}
-
-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);
- EVUTIL_ASSERT(req != NULL);
-
- EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
-
- /* We need to wait until we've written all of our output data before we can continue */
- if (evbuffer_get_length(bufferevent_get_output(evcon->bufev)) > 0) { return; }
-
- /* We are done writing our header and are now expecting the response */
- req->kind = EVHTTP_RESPONSE;
-
- evhttp_start_read_(evcon);
-}
-
-/*
- * Clean up a connection object
- */
-
-void
-evhttp_connection_free(struct evhttp_connection *evcon)
-{
- struct evhttp_request *req;
-
- /* notify interested parties that this connection is going down */
- if (evcon->fd != -1) {
- if (evhttp_connected(evcon) && evcon->closecb != NULL)
- (*evcon->closecb)(evcon, evcon->closecb_arg);
- }
-
- /* remove all requests that might be queued on this
- * connection. for server connections, this should be empty.
- * because it gets dequeued either in evhttp_connection_done or
- * evhttp_connection_fail_.
- */
- while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
- evhttp_request_free_(evcon, req);
- }
-
- if (evcon->http_server != NULL) {
- struct evhttp *http = evcon->http_server;
- TAILQ_REMOVE(&http->connections, evcon, next);
- }
-
- if (event_initialized(&evcon->retry_ev)) {
- event_del(&evcon->retry_ev);
- event_debug_unassign(&evcon->retry_ev);
- }
-
- if (evcon->bufev != NULL)
- bufferevent_free(evcon->bufev);
-
- event_deferred_cb_cancel_(get_deferred_queue(evcon),
- &evcon->read_more_deferred_cb);
-
- if (evcon->fd != -1) {
- bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
- shutdown(evcon->fd, EVUTIL_SHUT_WR);
- if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
- evutil_closesocket(evcon->fd);
- }
- }
-
- if (evcon->bind_address != NULL)
- mm_free(evcon->bind_address);
-
- if (evcon->address != NULL)
- mm_free(evcon->address);
-
- mm_free(evcon);
-}
-
-void
-evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
- evcon->flags |= EVHTTP_CON_AUTOFREE;
-}
-
-void
-evhttp_connection_set_local_address(struct evhttp_connection *evcon,
- const char *address)
-{
- EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
- if (evcon->bind_address)
- mm_free(evcon->bind_address);
- if ((evcon->bind_address = mm_strdup(address)) == NULL)
- event_warn("%s: strdup", __func__);
-}
-
-void
-evhttp_connection_set_local_port(struct evhttp_connection *evcon,
- ev_uint16_t port)
-{
- EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
- evcon->bind_port = port;
-}
-
-static void
-evhttp_request_dispatch(struct evhttp_connection* evcon)
-{
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
-
- /* this should not usually happy but it's possible */
- if (req == NULL)
- return;
-
- /* delete possible close detection events */
- evhttp_connection_stop_detectclose(evcon);
-
- /* we assume that the connection is connected already */
- EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
-
- evcon->state = EVCON_WRITING;
-
- /* Create the header from the store arguments */
- evhttp_make_header(evcon, req);
-
- evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
-}
-
-/* Reset our connection state: disables reading/writing, closes our fd (if
-* any), clears out buffers, and puts us in state DISCONNECTED. */
-void
-evhttp_connection_reset_(struct evhttp_connection *evcon)
-{
- struct evbuffer *tmp;
-
- /* XXXX This is not actually an optimal fix. Instead we ought to have
- an API for "stop connecting", or use bufferevent_setfd to turn off
- connecting. But for Libevent 2.0, this seems like a minimal change
- least likely to disrupt the rest of the bufferevent and http code.
-
- Why is this here? If the fd is set in the bufferevent, and the
- bufferevent is connecting, then you can't actually stop the
- bufferevent from trying to connect with bufferevent_disable(). The
- connect will never trigger, since we close the fd, but the timeout
- might. That caused an assertion failure in evhttp_connection_fail_.
- */
- bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
-
- if (evcon->fd != -1) {
- /* inform interested parties about connection close */
- if (evhttp_connected(evcon) && evcon->closecb != NULL)
- (*evcon->closecb)(evcon, evcon->closecb_arg);
-
- shutdown(evcon->fd, EVUTIL_SHUT_WR);
- evutil_closesocket(evcon->fd);
- bufferevent_setfd(evcon->bufev, -1);
- evcon->fd = -1;
- }
-
- /* we need to clean up any buffered data */
- tmp = bufferevent_get_output(evcon->bufev);
- evbuffer_drain(tmp, evbuffer_get_length(tmp));
- tmp = bufferevent_get_input(evcon->bufev);
- evbuffer_drain(tmp, evbuffer_get_length(tmp));
-
- evcon->state = EVCON_DISCONNECTED;
-}
-
-static void
-evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
-{
- evcon->flags |= EVHTTP_CON_CLOSEDETECT;
-
- bufferevent_enable(evcon->bufev, EV_READ);
-}
-
-static void
-evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
-{
- evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
-
- bufferevent_disable(evcon->bufev, EV_READ);
-}
-
-static void
-evhttp_connection_retry(evutil_socket_t fd, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
-
- evcon->state = EVCON_DISCONNECTED;
- evhttp_connection_connect_(evcon);
-}
-
-static void
-evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
-{
- struct evcon_requestq requests;
-
- evhttp_connection_reset_(evcon);
- if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
- struct timeval tv_retry = evcon->initial_retry_timeout;
- int i;
- evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon);
- /* XXXX handle failure from evhttp_add_event */
- for (i=0; i < evcon->retry_cnt; ++i) {
- tv_retry.tv_usec *= 2;
- if (tv_retry.tv_usec > 1000000) {
- tv_retry.tv_usec -= 1000000;
- tv_retry.tv_sec += 1;
- }
- tv_retry.tv_sec *= 2;
- if (tv_retry.tv_sec > 3600) {
- tv_retry.tv_sec = 3600;
- tv_retry.tv_usec = 0;
- }
- }
- event_add(&evcon->retry_ev, &tv_retry);
- evcon->retry_cnt++;
- return;
- }
-
- /*
- * User callback can do evhttp_make_request() on the same
- * evcon so new request will be added to evcon->requests. To
- * avoid freeing it prematurely we iterate over the copy of
- * the queue.
- */
- TAILQ_INIT(&requests);
- while (TAILQ_FIRST(&evcon->requests) != NULL) {
- struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
- TAILQ_REMOVE(&evcon->requests, request, next);
- TAILQ_INSERT_TAIL(&requests, request, next);
- }
-
- /* for now, we just signal all requests by executing their callbacks */
- while (TAILQ_FIRST(&requests) != NULL) {
- struct evhttp_request *request = TAILQ_FIRST(&requests);
- TAILQ_REMOVE(&requests, request, next);
- request->evcon = NULL;
-
- /* we might want to set an error here */
- request->cb(request, request->cb_arg);
- evhttp_request_free_auto(request);
- }
-}
-
-static void
-evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
-
- if (evcon->fd == -1)
- evcon->fd = bufferevent_getfd(bufev);
-
- switch (evcon->state) {
- case EVCON_CONNECTING:
- if (what & BEV_EVENT_TIMEOUT) {
- event_debug(("%s: connection timeout for \"%s:%d\" on "
- EV_SOCK_FMT,
- __func__, evcon->address, evcon->port,
- EV_SOCK_ARG(evcon->fd)));
- evhttp_connection_cb_cleanup(evcon);
- return;
- }
- break;
-
- case EVCON_READING_BODY:
- if (!req->chunked && req->ntoread < 0
- && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) {
- /* EOF on read can be benign */
- evhttp_connection_done(evcon);
- return;
- }
- break;
-
- case EVCON_DISCONNECTED:
- case EVCON_IDLE:
- case EVCON_READING_FIRSTLINE:
- case EVCON_READING_HEADERS:
- case EVCON_READING_TRAILER:
- case EVCON_WRITING:
- default:
- break;
- }
-
- /* when we are in close detect mode, a read error means that
- * the other side closed their connection.
- */
- if (evcon->flags & EVHTTP_CON_CLOSEDETECT) {
- evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
- EVUTIL_ASSERT(evcon->http_server == NULL);
- /* For connections from the client, we just
- * reset the connection so that it becomes
- * disconnected.
- */
- EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
- evhttp_connection_reset_(evcon);
-
- /*
- * If we have no more requests that need completion
- * and we want to auto-free the connection when all
- * requests have been completed.
- */
- if (TAILQ_FIRST(&evcon->requests) == NULL
- && (evcon->flags & EVHTTP_CON_OUTGOING)
- && (evcon->flags & EVHTTP_CON_AUTOFREE)) {
- evhttp_connection_free(evcon);
- }
- return;
- }
-
- if (what & BEV_EVENT_TIMEOUT) {
- evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
- } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
- evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
- } else if (what == BEV_EVENT_CONNECTED) {
- } else {
- evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
- }
-}
-
-/*
- * Event callback for asynchronous connection attempt.
- */
-static void
-evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
-{
- struct evhttp_connection *evcon = arg;
- int error;
- ev_socklen_t errsz = sizeof(error);
-
- if (evcon->fd == -1)
- evcon->fd = bufferevent_getfd(bufev);
-
- if (!(what & BEV_EVENT_CONNECTED)) {
- /* some operating systems return ECONNREFUSED immediately
- * when connecting to a local address. the cleanup is going
- * to reschedule this function call.
- */
-#ifndef _WIN32
- if (errno == ECONNREFUSED)
- goto cleanup;
-#endif
- evhttp_error_cb(bufev, what, arg);
- return;
- }
-
- if (evcon->fd == -1) {
- event_debug(("%s: bufferevent_getfd returned -1",
- __func__));
- 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 "EV_SOCK_FMT,
- __func__, evcon->address, evcon->port,
- EV_SOCK_ARG(evcon->fd)));
- goto cleanup;
- }
-
- if (error) {
- event_debug(("%s: connect failed for \"%s:%d\" on "
- EV_SOCK_FMT": %s",
- __func__, evcon->address, evcon->port,
- EV_SOCK_ARG(evcon->fd),
- evutil_socket_error_to_string(error)));
- goto cleanup;
- }
-
- /* We are connected to the server now */
- event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n",
- __func__, evcon->address, evcon->port,
- EV_SOCK_ARG(evcon->fd)));
-
- /* Reset the retry count as we were successful in connecting */
- evcon->retry_cnt = 0;
- evcon->state = EVCON_IDLE;
-
- /* reset the bufferevent cbs */
- bufferevent_setcb(evcon->bufev,
- evhttp_read_cb,
- evhttp_write_cb,
- evhttp_error_cb,
- evcon);
-
- if (!evutil_timerisset(&evcon->timeout)) {
- const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
- const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
- bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
- } else {
- bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
- }
-
- /* try to start requests that have queued up on this connection */
- evhttp_request_dispatch(evcon);
- return;
-
- cleanup:
- evhttp_connection_cb_cleanup(evcon);
-}
-
-/*
- * Check if we got a valid response code.
- */
-
-static int
-evhttp_valid_response_code(int code)
-{
- if (code == 0)
- return (0);
-
- return (1);
-}
-
-static int
-evhttp_parse_http_version(const char *version, struct evhttp_request *req)
-{
- int major, minor;
- char ch;
- int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch);
- if (n != 2 || major > 1) {
- event_debug(("%s: bad version %s on message %p from %s",
- __func__, version, req, req->remote_host));
- return (-1);
- }
- req->major = major;
- req->minor = minor;
- return (0);
-}
-
-/* Parses the status line of a web server */
-
-static int
-evhttp_parse_response_line(struct evhttp_request *req, char *line)
-{
- char *protocol;
- char *number;
- const char *readable = "";
-
- protocol = strsep(&line, " ");
- if (line == NULL)
- return (-1);
- number = strsep(&line, " ");
- if (line != NULL)
- readable = line;
-
- if (evhttp_parse_http_version(protocol, req) < 0)
- 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 = mm_strdup(readable)) == NULL) {
- event_warn("%s: strdup", __func__);
- return (-1);
- }
-
- 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;
- const char *hostname;
- const char *scheme;
- size_t method_len;
- enum evhttp_cmd_type type;
-
- /* 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);
-
- method_len = (uri - method) - 1;
- type = EVHTTP_REQ_UNKNOWN_;
-
- /* First line */
- switch (method_len) {
- case 3:
- /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
-
- /* Since both GET and PUT share the same character 'T' at the end,
- * if the string doesn't have 'T', we can immediately determine this
- * is an invalid HTTP method */
-
- if (method[2] != 'T') {
- break;
- }
-
- switch (*method) {
- case 'G':
- /* This first byte is 'G', so make sure the next byte is
- * 'E', if it isn't then this isn't a valid method */
-
- if (method[1] == 'E') {
- type = EVHTTP_REQ_GET;
- }
-
- break;
- case 'P':
- /* First byte is P, check second byte for 'U', if not,
- * we know it's an invalid method */
- if (method[1] == 'U') {
- type = EVHTTP_REQ_PUT;
- }
- break;
- default:
- break;
- }
- break;
- case 4:
- /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
- switch (*method) {
- case 'P':
- if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
- type = EVHTTP_REQ_POST;
- }
- break;
- case 'H':
- if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
- type = EVHTTP_REQ_HEAD;
- }
- break;
- default:
- break;
- }
- break;
- case 5:
- /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
- switch (*method) {
- case 'P':
- if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
- type = EVHTTP_REQ_PATCH;
- }
- break;
- case 'T':
- if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
- type = EVHTTP_REQ_TRACE;
- }
-
- break;
- default:
- break;
- }
- break;
- case 6:
- /* Method length is 6, only valid method 6 bytes in length is DELEte */
-
- /* If the first byte isn't 'D' then it's invalid */
- if (*method != 'D') {
- break;
- }
-
- if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
- type = EVHTTP_REQ_DELETE;
- }
-
- break;
- case 7:
- /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
- switch (*method) {
- case 'O':
- if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
- method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
- type = EVHTTP_REQ_OPTIONS;
- }
-
- break;
- case 'C':
- if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
- method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
- type = EVHTTP_REQ_CONNECT;
- }
-
- break;
- default:
- break;
- }
- break;
- } /* switch */
-
- if ((int)type == EVHTTP_REQ_UNKNOWN_) {
- event_debug(("%s: bad method %s on request %p from %s",
- __func__, method, req, req->remote_host));
- /* No error yet; we'll give a better error later when
- * we see that req->type is unsupported. */
- }
-
- req->type = type;
-
- if (evhttp_parse_http_version(version, req) < 0)
- return (-1);
-
- if ((req->uri = mm_strdup(uri)) == NULL) {
- event_debug(("%s: mm_strdup", __func__));
- return (-1);
- }
-
- if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
- EVHTTP_URI_NONCONFORMANT)) == NULL) {
- return -1;
- }
-
- /* If we have an absolute-URI, check to see if it is an http request
- for a known vhost or server alias. If we don't know about this
- host, we consider it a proxy request. */
- scheme = evhttp_uri_get_scheme(req->uri_elems);
- hostname = evhttp_uri_get_host(req->uri_elems);
- if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") ||
- !evutil_ascii_strcasecmp(scheme, "https")) &&
- hostname &&
- !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
- 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 (evutil_ascii_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);
- mm_free(header->key);
- mm_free(header->value);
- mm_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 (evutil_ascii_strcasecmp(header->key, key) == 0)
- break;
- }
-
- if (header == NULL)
- return (-1);
-
- /* Free and remove the header that we found */
- TAILQ_REMOVE(headers, header, next);
- mm_free(header->key);
- mm_free(header->value);
- mm_free(header);
-
- return (0);
-}
-
-static int
-evhttp_header_is_valid_value(const char *value)
-{
- const char *p = value;
-
- while ((p = strpbrk(p, "\r\n")) != NULL) {
- /* we really expect only one new line */
- p += strspn(p, "\r\n");
- /* we expect a space or tab for continuation */
- if (*p != ' ' && *p != '\t')
- return (0);
- }
- return (1);
-}
-
-int
-evhttp_add_header(struct evkeyvalq *headers,
- const char *key, const char *value)
-{
- event_debug(("%s: key: %s val: %s\n", __func__, key, value));
-
- if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
- /* drop illegal headers */
- event_debug(("%s: dropping illegal header key\n", __func__));
- return (-1);
- }
-
- if (!evhttp_header_is_valid_value(value)) {
- event_debug(("%s: dropping illegal header value\n", __func__));
- return (-1);
- }
-
- return (evhttp_add_header_internal(headers, key, value));
-}
-
-static int
-evhttp_add_header_internal(struct evkeyvalq *headers,
- const char *key, const char *value)
-{
- struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval));
- if (header == NULL) {
- event_warn("%s: calloc", __func__);
- return (-1);
- }
- if ((header->key = mm_strdup(key)) == NULL) {
- mm_free(header);
- event_warn("%s: strdup", __func__);
- return (-1);
- }
- if ((header->value = mm_strdup(value)) == NULL) {
- mm_free(header->key);
- mm_free(header);
- event_warn("%s: strdup", __func__);
- return (-1);
- }
-
- TAILQ_INSERT_TAIL(headers, header, next);
-
- return (0);
-}
-
-/*
- * Parses header lines from a request or a response into the specified
- * request object given an event buffer.
- *
- * Returns
- * DATA_CORRUPTED on error
- * MORE_DATA_EXPECTED when we need to read more headers
- * ALL_DATA_READ when all headers have been read.
- */
-
-enum message_read_status
-evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
-{
- char *line;
- enum message_read_status status = ALL_DATA_READ;
-
- size_t line_length;
- /* XXX try */
- line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF);
- if (line == NULL) {
- if (req->evcon != NULL &&
- evbuffer_get_length(buffer) > req->evcon->max_headers_size)
- return (DATA_TOO_LONG);
- else
- return (MORE_DATA_EXPECTED);
- }
-
- if (req->evcon != NULL &&
- line_length > req->evcon->max_headers_size) {
- mm_free(line);
- return (DATA_TOO_LONG);
- }
-
- req->headers_size = line_length;
-
- switch (req->kind) {
- case EVHTTP_REQUEST:
- if (evhttp_parse_request_line(req, line) == -1)
- status = DATA_CORRUPTED;
- break;
- case EVHTTP_RESPONSE:
- if (evhttp_parse_response_line(req, line) == -1)
- status = DATA_CORRUPTED;
- break;
- default:
- status = DATA_CORRUPTED;
- }
-
- mm_free(line);
- return (status);
-}
-
-static int
-evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
-{
- struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
- char *newval;
- size_t old_len, line_len;
-
- if (header == NULL)
- return (-1);
-
- old_len = strlen(header->value);
-
- /* Strip space from start and end of line. */
- while (*line == ' ' || *line == '\t')
- ++line;
- evutil_rtrim_lws_(line);
-
- line_len = strlen(line);
-
- newval = mm_realloc(header->value, old_len + line_len + 2);
- if (newval == NULL)
- return (-1);
-
- newval[old_len] = ' ';
- memcpy(newval + old_len + 1, line, line_len + 1);
- header->value = newval;
-
- return (0);
-}
-
-enum message_read_status
-evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
-{
- enum message_read_status errcode = DATA_CORRUPTED;
- char *line;
- enum message_read_status status = MORE_DATA_EXPECTED;
-
- struct evkeyvalq* headers = req->input_headers;
- size_t line_length;
- while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF))
- != NULL) {
- char *skey, *svalue;
-
- req->headers_size += line_length;
-
- if (req->evcon != NULL &&
- req->headers_size > req->evcon->max_headers_size) {
- errcode = DATA_TOO_LONG;
- goto error;
- }
-
- if (*line == '\0') { /* Last header - Done */
- status = ALL_DATA_READ;
- mm_free(line);
- break;
- }
-
- /* Check if this is a continuation line */
- if (*line == ' ' || *line == '\t') {
- if (evhttp_append_to_last_header(headers, line) == -1)
- goto error;
- mm_free(line);
- continue;
- }
-
- /* Processing of header lines */
- svalue = line;
- skey = strsep(&svalue, ":");
- if (svalue == NULL)
- goto error;
-
- svalue += strspn(svalue, " ");
- evutil_rtrim_lws_(svalue);
-
- if (evhttp_add_header(headers, skey, svalue) == -1)
- goto error;
-
- mm_free(line);
- }
-
- if (status == MORE_DATA_EXPECTED) {
- if (req->evcon != NULL &&
- req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size)
- return (DATA_TOO_LONG);
- }
-
- return (status);
-
- error:
- mm_free(line);
- return (errcode);
-}
-
-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 &&
- evutil_ascii_strcasecmp(connection, "Close") != 0) {
- /* Bad combination, we don't know when it will end */
- event_warnx("%s: we got no content length, but the "
- "server wants to keep the connection open: %s.",
- __func__, connection);
- return (-1);
- } else if (content_length == NULL) {
- req->ntoread = -1;
- } else {
- char *endp;
- ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
- if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
- event_debug(("%s: illegal content length: %s",
- __func__, content_length));
- return (-1);
- }
- req->ntoread = ntoread;
- }
-
- event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n",
- __func__, EV_I64_ARG(req->ntoread),
- EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev)))));
-
- return (0);
-}
-
-static int
-evhttp_method_may_have_body(enum evhttp_cmd_type type)
-{
- switch (type) {
- case EVHTTP_REQ_POST:
- case EVHTTP_REQ_PUT:
- case EVHTTP_REQ_PATCH:
- return 1;
- case EVHTTP_REQ_TRACE:
- return 0;
- /* XXX May any of the below methods have a body? */
- case EVHTTP_REQ_GET:
- case EVHTTP_REQ_HEAD:
- case EVHTTP_REQ_DELETE:
- case EVHTTP_REQ_OPTIONS:
- case EVHTTP_REQ_CONNECT:
- return 0;
- default:
- 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 &&
- !evhttp_method_may_have_body(req->type)) {
- evhttp_connection_done(evcon);
- return;
- }
- evcon->state = EVCON_READING_BODY;
- xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
- if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) {
- req->chunked = 1;
- req->ntoread = -1;
- } else {
- if (evhttp_get_body_length(req) == -1) {
- evhttp_connection_fail_(evcon,
- EVREQ_HTTP_INVALID_HEADER);
- return;
- }
- if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
- /* An incoming request with no content-length and no
- * transfer-encoding has no body. */
- evhttp_connection_done(evcon);
- return;
- }
- }
-
- /* Should we send a 100 Continue status line? */
- if (req->kind == EVHTTP_REQUEST && REQ_VERSION_ATLEAST(req, 1, 1)) {
- const char *expect;
-
- expect = evhttp_find_header(req->input_headers, "Expect");
- if (expect) {
- if (!evutil_ascii_strcasecmp(expect, "100-continue")) {
- /* XXX It would be nice to do some sanity
- checking here. Does the resource exist?
- Should the resource accept post requests? If
- no, we should respond with an error. For
- now, just optimistically tell the client to
- send their message body. */
- if (req->ntoread > 0) {
- /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
- if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
- evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL);
- return;
- }
- }
- if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
- evhttp_send_continue(evcon, req);
- } else {
- evhttp_send_error(req, HTTP_EXPECTATIONFAILED,
- NULL);
- return;
- }
- }
- }
-
- evhttp_read_body(evcon, req);
- /* note the request may have been freed in evhttp_read_body */
-}
-
-static void
-evhttp_read_firstline(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- enum message_read_status res;
-
- res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev));
- if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
- /* Error while reading, terminate */
- event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
- __func__, EV_SOCK_ARG(evcon->fd)));
- evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
- return;
- } else if (res == MORE_DATA_EXPECTED) {
- /* Need more header lines */
- return;
- }
-
- evcon->state = EVCON_READING_HEADERS;
- evhttp_read_header(evcon, req);
-}
-
-static void
-evhttp_read_header(struct evhttp_connection *evcon,
- struct evhttp_request *req)
-{
- enum message_read_status res;
- evutil_socket_t fd = evcon->fd;
-
- res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev));
- if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
- /* Error while reading, terminate */
- event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
- __func__, EV_SOCK_ARG(fd)));
- evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
- return;
- } else if (res == MORE_DATA_EXPECTED) {
- /* Need more header lines */
- return;
- }
-
- /* Callback can shut down connection with negative return value */
- if (req->header_cb != NULL) {
- if ((*req->header_cb)(req, req->cb_arg) < 0) {
- evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
- return;
- }
- }
-
- /* Done reading headers, do the real work */
- switch (req->kind) {
- case EVHTTP_REQUEST:
- event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n",
- __func__, EV_SOCK_ARG(fd)));
- evhttp_get_body(evcon, req);
- /* note the request may have been freed in evhttp_get_body */
- break;
-
- case EVHTTP_RESPONSE:
- /* Start over if we got a 100 Continue response. */
- if (req->response_code == 100) {
- evhttp_start_read_(evcon);
- return;
- }
- if (!evhttp_response_needs_body(req)) {
- 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 "
- EV_SOCK_FMT"\n",
- __func__, req->remote_host, EV_SOCK_ARG(fd)));
- evhttp_get_body(evcon, req);
- /* note the request may have been freed in
- * evhttp_get_body */
- }
- break;
-
- default:
- event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
- EV_SOCK_ARG(fd));
- evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
- break;
- }
- /* request may have been freed above */
-}
-
-/*
- * Creates a TCP connection to the specified port and executes a callback
- * when finished. Failure or success 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)
-{
- return (evhttp_connection_base_new(NULL, NULL, address, port));
-}
-
-struct evhttp_connection *
-evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
- const char *address, unsigned short port)
-{
- struct evhttp_connection *evcon = NULL;
-
- event_debug(("Attempting connection to %s:%d\n", address, port));
-
- if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
- event_warn("%s: calloc failed", __func__);
- goto error;
- }
-
- evcon->fd = -1;
- evcon->port = port;
-
- evcon->max_headers_size = EV_SIZE_MAX;
- evcon->max_body_size = EV_SIZE_MAX;
-
- evutil_timerclear(&evcon->timeout);
- evcon->retry_cnt = evcon->retry_max = 0;
-
- if ((evcon->address = mm_strdup(address)) == NULL) {
- event_warn("%s: strdup failed", __func__);
- goto error;
- }
-
- if (bev == NULL) {
- if (!(bev = bufferevent_socket_new(base, -1, 0))) {
- event_warn("%s: bufferevent_socket_new failed", __func__);
- goto error;
- }
- }
-
- bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
- evcon->bufev = bev;
-
- evcon->state = EVCON_DISCONNECTED;
- TAILQ_INIT(&evcon->requests);
-
- evcon->initial_retry_timeout.tv_sec = 2;
- evcon->initial_retry_timeout.tv_usec = 0;
-
- if (base != NULL) {
- evcon->base = base;
- if (bufferevent_get_base(bev) != base)
- bufferevent_base_set(base, evcon->bufev);
- }
-
- event_deferred_cb_init_(
- &evcon->read_more_deferred_cb,
- bufferevent_get_priority(bev),
- evhttp_deferred_read_cb, evcon);
-
- evcon->dns_base = dnsbase;
- evcon->ai_family = AF_UNSPEC;
-
- return (evcon);
-
- error:
- if (evcon != NULL)
- evhttp_connection_free(evcon);
- return (NULL);
-}
-
-struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
-{
- return evcon->bufev;
-}
-
-struct evhttp *
-evhttp_connection_get_server(struct evhttp_connection *evcon)
-{
- return evcon->http_server;
-}
-
-struct evhttp_connection *
-evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
- const char *address, unsigned short port)
-{
- return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
-}
-
-void evhttp_connection_set_family(struct evhttp_connection *evcon,
- int family)
-{
- evcon->ai_family = family;
-}
-
-int evhttp_connection_set_flags(struct evhttp_connection *evcon,
- int flags)
-{
- int avail_flags = 0;
- avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
-
- if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
- return 1;
- evcon->flags &= ~avail_flags;
-
- evcon->flags |= flags;
-
- return 0;
-}
-
-void
-evhttp_connection_set_base(struct evhttp_connection *evcon,
- struct event_base *base)
-{
- EVUTIL_ASSERT(evcon->base == NULL);
- EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
- evcon->base = base;
- bufferevent_base_set(base, evcon->bufev);
-}
-
-void
-evhttp_connection_set_timeout(struct evhttp_connection *evcon,
- int timeout_in_secs)
-{
- if (timeout_in_secs == -1)
- evhttp_connection_set_timeout_tv(evcon, NULL);
- else {
- struct timeval tv;
- tv.tv_sec = timeout_in_secs;
- tv.tv_usec = 0;
- evhttp_connection_set_timeout_tv(evcon, &tv);
- }
-}
-
-void
-evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
- const struct timeval* tv)
-{
- if (tv) {
- evcon->timeout = *tv;
- bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
- } else {
- const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
- const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
- evutil_timerclear(&evcon->timeout);
- bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
- }
-}
-
-void
-evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
- const struct timeval *tv)
-{
- if (tv) {
- evcon->initial_retry_timeout = *tv;
- } else {
- evutil_timerclear(&evcon->initial_retry_timeout);
- evcon->initial_retry_timeout.tv_sec = 2;
- }
-}
-
-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, ev_uint16_t *port)
-{
- *address = evcon->address;
- *port = evcon->port;
-}
-
-const struct sockaddr*
-evhttp_connection_get_addr(struct evhttp_connection *evcon)
-{
- return bufferevent_socket_get_conn_address_(evcon->bufev);
-}
-
-int
-evhttp_connection_connect_(struct evhttp_connection *evcon)
-{
- int old_state = evcon->state;
- const char *address = evcon->address;
- const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
- int ret;
-
- if (evcon->state == EVCON_CONNECTING)
- return (0);
-
- evhttp_connection_reset_(evcon);
-
- EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING));
- evcon->flags |= EVHTTP_CON_OUTGOING;
-
- if (evcon->bind_address || evcon->bind_port) {
- evcon->fd = bind_socket(
- evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
- if (evcon->fd == -1) {
- event_debug(("%s: failed to bind to \"%s\"",
- __func__, evcon->bind_address));
- return (-1);
- }
-
- bufferevent_setfd(evcon->bufev, evcon->fd);
- } else {
- bufferevent_setfd(evcon->bufev, -1);
- }
-
- /* Set up a callback for successful connection setup */
- bufferevent_setcb(evcon->bufev,
- NULL /* evhttp_read_cb */,
- NULL /* evhttp_write_cb */,
- evhttp_connection_cb,
- evcon);
- if (!evutil_timerisset(&evcon->timeout)) {
- const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
- bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
- } else {
- bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
- }
- /* make sure that we get a write callback */
- bufferevent_enable(evcon->bufev, EV_WRITE);
-
- evcon->state = EVCON_CONNECTING;
-
- if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
- sa &&
- (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
- int socklen = sizeof(struct sockaddr_in);
- if (sa->sa_family == AF_INET6) {
- socklen = sizeof(struct sockaddr_in6);
- }
- ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
- } else {
- ret = bufferevent_socket_connect_hostname(evcon->bufev,
- evcon->dns_base, evcon->ai_family, address, evcon->port);
- }
-
- if (ret < 0) {
- evcon->state = old_state;
- event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
- __func__, evcon->address);
- /* some operating systems return ECONNREFUSED immediately
- * when connecting to a local address. the cleanup is going
- * to reschedule this function call.
- */
- evhttp_connection_cb_cleanup(evcon);
- return (0);
- }
-
- 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)
- mm_free(req->uri);
- if ((req->uri = mm_strdup(uri)) == NULL) {
- event_warn("%s: strdup", __func__);
- evhttp_request_free_auto(req);
- return (-1);
- }
-
- /* Set the protocol version if it is not supplied */
- if (!req->major && !req->minor) {
- req->major = 1;
- req->minor = 1;
- }
-
- EVUTIL_ASSERT(req->evcon == NULL);
- req->evcon = evcon;
- EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
-
- TAILQ_INSERT_TAIL(&evcon->requests, req, next);
-
- /* If the connection object is not connected; make it so */
- if (!evhttp_connected(evcon)) {
- int res = evhttp_connection_connect_(evcon);
- /* evhttp_connection_fail_(), which is called through
- * evhttp_connection_connect_(), assumes that req lies in
- * evcon->requests. Thus, enqueue the request in advance and
- * remove it in the error case. */
- if (res != 0)
- TAILQ_REMOVE(&evcon->requests, req, next);
-
- return res;
- }
-
- /*
- * 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);
-}
-
-void
-evhttp_cancel_request(struct evhttp_request *req)
-{
- struct evhttp_connection *evcon = req->evcon;
- if (evcon != NULL) {
- /* We need to remove it from the connection */
- if (TAILQ_FIRST(&evcon->requests) == req) {
- /* it's currently being worked on, so reset
- * the connection.
- */
- evhttp_connection_fail_(evcon,
- EVREQ_HTTP_REQUEST_CANCEL);
-
- /* connection fail freed the request */
- return;
- } else {
- /* otherwise, we can just remove it from the
- * queue
- */
- TAILQ_REMOVE(&evcon->requests, req, next);
- }
- }
-
- evhttp_request_free_auto(req);
-}
-
-/*
- * Reads data from file descriptor into request structure
- * Request structure needs to be set up correctly.
- */
-
-void
-evhttp_start_read_(struct evhttp_connection *evcon)
-{
- bufferevent_disable(evcon->bufev, EV_WRITE);
- bufferevent_enable(evcon->bufev, EV_READ);
-
- evcon->state = EVCON_READING_FIRSTLINE;
- /* Reset the bufferevent callbacks */
- bufferevent_setcb(evcon->bufev,
- evhttp_read_cb,
- evhttp_write_cb,
- evhttp_error_cb,
- evcon);
-
- /* If there's still data pending, process it next time through the
- * loop. Don't do it now; that could get recusive. */
- if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) {
- event_deferred_cb_schedule_(get_deferred_queue(evcon),
- &evcon->read_more_deferred_cb);
- }
-}
-
-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);
-
- if (req->on_complete_cb != NULL) {
- req->on_complete_cb(req, req->on_complete_cb_arg);
- }
-
- need_close =
- (REQ_VERSION_BEFORE(req, 1, 1) &&
- !evhttp_is_connection_keepalive(req->input_headers)) ||
- evhttp_is_request_connection_close(req);
-
- EVUTIL_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>%s</H1>\n" \
- "</BODY></HTML>\n"
-
- struct evbuffer *buf = evbuffer_new();
- if (buf == NULL) {
- /* if we cannot allocate memory; we just drop the connection */
- evhttp_connection_free(req->evcon);
- return;
- }
- if (reason == NULL) {
- reason = evhttp_response_phrase_internal(error);
- }
-
- evhttp_response_code_(req, error, reason);
-
- evbuffer_add_printf(buf, ERR_FORMAT, error, reason, 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;
-
- if (evcon == NULL) {
- evhttp_request_free(req);
- return;
- }
-
- EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req);
-
- /* we expect no more calls form the user on this request */
- req->userdone = 1;
-
- /* xxx: not sure if we really should expose the data buffer this way */
- if (databuf != NULL)
- evbuffer_add_buffer(req->output_buffer, databuf);
-
- /* Adds headers to the response */
- evhttp_make_header(evcon, req);
-
- evhttp_write_buffer(evcon, evhttp_send_done, NULL);
-}
-
-void
-evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
- struct evbuffer *databuf)
-{
- evhttp_response_code_(req, code, reason);
-
- evhttp_send(req, databuf);
-}
-
-void
-evhttp_send_reply_start(struct evhttp_request *req, int code,
- const char *reason)
-{
- evhttp_response_code_(req, code, reason);
- if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
- REQ_VERSION_ATLEAST(req, 1, 1) &&
- evhttp_response_needs_body(req)) {
- /*
- * prefer HTTP/1.1 chunked encoding to closing the connection;
- * note RFC 2616 section 4.4 forbids it with Content-Length:
- * and it's not necessary then anyway.
- */
- evhttp_add_header(req->output_headers, "Transfer-Encoding",
- "chunked");
- req->chunked = 1;
- } else {
- req->chunked = 0;
- }
- evhttp_make_header(req->evcon, req);
- evhttp_write_buffer(req->evcon, NULL, NULL);
-}
-
-void
-evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
- void (*cb)(struct evhttp_connection *, void *), void *arg)
-{
- struct evhttp_connection *evcon = req->evcon;
- struct evbuffer *output;
-
- if (evcon == NULL)
- return;
-
- output = bufferevent_get_output(evcon->bufev);
-
- if (evbuffer_get_length(databuf) == 0)
- return;
- if (!evhttp_response_needs_body(req))
- return;
- if (req->chunked) {
- evbuffer_add_printf(output, "%x\r\n",
- (unsigned)evbuffer_get_length(databuf));
- }
- evbuffer_add_buffer(output, databuf);
- if (req->chunked) {
- evbuffer_add(output, "\r\n", 2);
- }
- evhttp_write_buffer(evcon, cb, arg);
-}
-
-void
-evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
-{
- evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
-}
-void
-evhttp_send_reply_end(struct evhttp_request *req)
-{
- struct evhttp_connection *evcon = req->evcon;
- struct evbuffer *output;
-
- if (evcon == NULL) {
- evhttp_request_free(req);
- return;
- }
-
- output = bufferevent_get_output(evcon->bufev);
-
- /* we expect no more calls form the user on this request */
- req->userdone = 1;
-
- if (req->chunked) {
- evbuffer_add(output, "0\r\n\r\n", 5);
- evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
- req->chunked = 0;
- } else if (evbuffer_get_length(output) == 0) {
- /* 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;
- }
-}
-
-static const char *informational_phrases[] = {
- /* 100 */ "Continue",
- /* 101 */ "Switching Protocols"
-};
-
-static const char *success_phrases[] = {
- /* 200 */ "OK",
- /* 201 */ "Created",
- /* 202 */ "Accepted",
- /* 203 */ "Non-Authoritative Information",
- /* 204 */ "No Content",
- /* 205 */ "Reset Content",
- /* 206 */ "Partial Content"
-};
-
-static const char *redirection_phrases[] = {
- /* 300 */ "Multiple Choices",
- /* 301 */ "Moved Permanently",
- /* 302 */ "Found",
- /* 303 */ "See Other",
- /* 304 */ "Not Modified",
- /* 305 */ "Use Proxy",
- /* 307 */ "Temporary Redirect"
-};
-
-static const char *client_error_phrases[] = {
- /* 400 */ "Bad Request",
- /* 401 */ "Unauthorized",
- /* 402 */ "Payment Required",
- /* 403 */ "Forbidden",
- /* 404 */ "Not Found",
- /* 405 */ "Method Not Allowed",
- /* 406 */ "Not Acceptable",
- /* 407 */ "Proxy Authentication Required",
- /* 408 */ "Request Time-out",
- /* 409 */ "Conflict",
- /* 410 */ "Gone",
- /* 411 */ "Length Required",
- /* 412 */ "Precondition Failed",
- /* 413 */ "Request Entity Too Large",
- /* 414 */ "Request-URI Too Large",
- /* 415 */ "Unsupported Media Type",
- /* 416 */ "Requested range not satisfiable",
- /* 417 */ "Expectation Failed"
-};
-
-static const char *server_error_phrases[] = {
- /* 500 */ "Internal Server Error",
- /* 501 */ "Not Implemented",
- /* 502 */ "Bad Gateway",
- /* 503 */ "Service Unavailable",
- /* 504 */ "Gateway Time-out",
- /* 505 */ "HTTP Version not supported"
-};
-
-struct response_class {
- const char *name;
- size_t num_responses;
- const char **responses;
-};
-
-#ifndef MEMBERSOF
-#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0]))
-#endif
-
-static const struct response_class response_classes[] = {
- /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases },
- /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases },
- /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases },
- /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases },
- /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases }
-};
-
-static const char *
-evhttp_response_phrase_internal(int code)
-{
- int klass = code / 100 - 1;
- int subcode = code % 100;
-
- /* Unknown class - can't do any better here */
- if (klass < 0 || klass >= (int) MEMBERSOF(response_classes))
- return "Unknown Status Class";
-
- /* Unknown sub-code, return class name at least */
- if (subcode >= (int) response_classes[klass].num_responses)
- return response_classes[klass].name;
-
- return response_classes[klass].responses[subcode];
-}
-
-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)
- mm_free(req->response_code_line);
- if (reason == NULL)
- reason = evhttp_response_phrase_internal(code);
- req->response_code_line = mm_strdup(reason);
- if (req->response_code_line == NULL) {
- event_warn("%s: strdup", __func__);
- /* XXX what else can we do? */
- }
-}
-
-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,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- /* 64 */
- 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, 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,
-};
-
-#define CHAR_IS_UNRESERVED(c) \
- (uri_chars[(unsigned char)(c)])
-
-/*
- * Helper functions to encode/decode a string for inclusion in a URI.
- * The returned string must be freed by the caller.
- */
-char *
-evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
-{
- struct evbuffer *buf = evbuffer_new();
- const char *p, *end;
- char *result;
-
- if (buf == NULL)
- return (NULL);
-
- if (len >= 0)
- end = uri+len;
- else
- end = uri+strlen(uri);
-
- for (p = uri; p < end; p++) {
- if (CHAR_IS_UNRESERVED(*p)) {
- evbuffer_add(buf, p, 1);
- } else if (*p == ' ' && space_as_plus) {
- evbuffer_add(buf, "+", 1);
- } else {
- evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
- }
- }
- evbuffer_add(buf, "", 1); /* NUL-terminator. */
- result = mm_malloc(evbuffer_get_length(buf));
- if (result)
- evbuffer_remove(buf, result, evbuffer_get_length(buf));
- evbuffer_free(buf);
-
- return (result);
-}
-
-char *
-evhttp_encode_uri(const char *str)
-{
- return evhttp_uriencode(str, -1, 0);
-}
-
-/*
- * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't.
- * If -1, when true we transform plus to space only after we've seen
- * a ?. -1 is deprecated.
- * @return the number of bytes written to 'ret'.
- */
-int
-evhttp_decode_uri_internal(
- const char *uri, size_t length, char *ret, int decode_plus_ctl)
-{
- char c;
- int j;
- int decode_plus = (decode_plus_ctl == 1) ? 1: 0;
- unsigned i;
-
- for (i = j = 0; i < length; i++) {
- c = uri[i];
- if (c == '?') {
- if (decode_plus_ctl < 0)
- decode_plus = 1;
- } else if (c == '+' && decode_plus) {
- c = ' ';
- } else if ((i + 2) < length && c == '%' &&
- EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) {
- char tmp[3];
- tmp[0] = uri[i+1];
- tmp[1] = uri[i+2];
- tmp[2] = '\0';
- c = (char)strtol(tmp, NULL, 16);
- i += 2;
- }
- ret[j++] = c;
- }
- ret[j] = '\0';
-
- return (j);
-}
-
-/* deprecated */
-char *
-evhttp_decode_uri(const char *uri)
-{
- char *ret;
-
- if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
- event_warn("%s: malloc(%lu)", __func__,
- (unsigned long)(strlen(uri) + 1));
- return (NULL);
- }
-
- evhttp_decode_uri_internal(uri, strlen(uri),
- ret, -1 /*always_decode_plus*/);
-
- return (ret);
-}
-
-char *
-evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
-{
- char *ret;
- int n;
-
- if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
- event_warn("%s: malloc(%lu)", __func__,
- (unsigned long)(strlen(uri) + 1));
- return (NULL);
- }
-
- n = evhttp_decode_uri_internal(uri, strlen(uri),
- ret, !!decode_plus/*always_decode_plus*/);
-
- if (size_out) {
- EVUTIL_ASSERT(n >= 0);
- *size_out = (size_t)n;
- }
-
- return (ret);
-}
-
-/*
- * Helper function to parse out arguments in a query.
- * The arguments are separated by key and value.
- */
-
-static int
-evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
- int is_whole_uri)
-{
- char *line=NULL;
- char *argument;
- char *p;
- const char *query_part;
- int result = -1;
- struct evhttp_uri *uri=NULL;
-
- TAILQ_INIT(headers);
-
- if (is_whole_uri) {
- uri = evhttp_uri_parse(str);
- if (!uri)
- goto error;
- query_part = evhttp_uri_get_query(uri);
- } else {
- query_part = str;
- }
-
- /* No arguments - we are done */
- if (!query_part || !strlen(query_part)) {
- result = 0;
- goto done;
- }
-
- if ((line = mm_strdup(query_part)) == NULL) {
- event_warn("%s: strdup", __func__);
- goto error;
- }
-
- p = argument = line;
- while (p != NULL && *p != '\0') {
- char *key, *value, *decoded_value;
- argument = strsep(&p, "&");
-
- value = argument;
- key = strsep(&value, "=");
- if (value == NULL || *key == '\0') {
- goto error;
- }
-
- if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
- event_warn("%s: mm_malloc", __func__);
- goto error;
- }
- evhttp_decode_uri_internal(value, strlen(value),
- decoded_value, 1 /*always_decode_plus*/);
- event_debug(("Query Param: %s -> %s\n", key, decoded_value));
- evhttp_add_header_internal(headers, key, decoded_value);
- mm_free(decoded_value);
- }
-
- result = 0;
- goto done;
-error:
- evhttp_clear_headers(headers);
-done:
- if (line)
- mm_free(line);
- if (uri)
- evhttp_uri_free(uri);
- return result;
-}
-
-int
-evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
-{
- return evhttp_parse_query_impl(uri, headers, 1);
-}
-int
-evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
-{
- return evhttp_parse_query_impl(uri, headers, 0);
-}
-
-static struct evhttp_cb *
-evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
-{
- struct evhttp_cb *cb;
- size_t offset = 0;
- char *translated;
- const char *path;
-
- /* Test for different URLs */
- path = evhttp_uri_get_path(req->uri_elems);
- offset = strlen(path);
- if ((translated = mm_malloc(offset + 1)) == NULL)
- return (NULL);
- evhttp_decode_uri_internal(path, offset, translated,
- 0 /* decode_plus */);
-
- TAILQ_FOREACH(cb, callbacks, next) {
- if (!strcmp(cb->what, translated)) {
- mm_free(translated);
- return (cb);
- }
- }
-
- mm_free(translated);
- return (NULL);
-}
-
-
-static int
-prefix_suffix_match(const char *pattern, const char *name, int ignorecase)
-{
- char c;
-
- while (1) {
- switch (c = *pattern++) {
- case '\0':
- return *name == '\0';
-
- case '*':
- while (*name != '\0') {
- if (prefix_suffix_match(pattern, name,
- ignorecase))
- return (1);
- ++name;
- }
- return (0);
- default:
- if (c != *name) {
- if (!ignorecase ||
- EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name))
- return (0);
- }
- ++name;
- }
- }
- /* NOTREACHED */
-}
-
-/*
- Search the vhost hierarchy beginning with http for a server alias
- matching hostname. If a match is found, and outhttp is non-null,
- outhttp is set to the matching http object and 1 is returned.
-*/
-
-static int
-evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp,
- const char *hostname)
-{
- struct evhttp_server_alias *alias;
- struct evhttp *vhost;
-
- TAILQ_FOREACH(alias, &http->aliases, next) {
- /* XXX Do we need to handle IP addresses? */
- if (!evutil_ascii_strcasecmp(alias->alias, hostname)) {
- if (outhttp)
- *outhttp = http;
- return 1;
- }
- }
-
- /* XXX It might be good to avoid recursion here, but I don't
- see a way to do that w/o a list. */
- TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
- if (evhttp_find_alias(vhost, outhttp, hostname))
- return 1;
- }
-
- return 0;
-}
-
-/*
- Attempts to find the best http object to handle a request for a hostname.
- All aliases for the root http object and vhosts are searched for an exact
- match. Then, the vhost hierarchy is traversed again for a matching
- pattern.
-
- If an alias or vhost is matched, 1 is returned, and outhttp, if non-null,
- is set with the best matching http object. If there are no matches, the
- root http object is stored in outhttp and 0 is returned.
-*/
-
-static int
-evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
- const char *hostname)
-{
- struct evhttp *vhost;
- struct evhttp *oldhttp;
- int match_found = 0;
-
- if (evhttp_find_alias(http, outhttp, hostname))
- return 1;
-
- do {
- oldhttp = http;
- TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
- if (prefix_suffix_match(vhost->vhost_pattern,
- hostname, 1 /* ignorecase */)) {
- http = vhost;
- match_found = 1;
- break;
- }
- }
- } while (oldhttp != http);
-
- if (outhttp)
- *outhttp = http;
-
- return match_found;
-}
-
-static void
-evhttp_handle_request(struct evhttp_request *req, void *arg)
-{
- struct evhttp *http = arg;
- struct evhttp_cb *cb = NULL;
- const char *hostname;
-
- /* we have a new request on which the user needs to take action */
- req->userdone = 0;
-
- if (req->type == 0 || req->uri == NULL) {
- evhttp_send_error(req, HTTP_BADREQUEST, NULL);
- return;
- }
-
- if ((http->allowed_methods & req->type) == 0) {
- event_debug(("Rejecting disallowed method %x (allowed: %x)\n",
- (unsigned)req->type, (unsigned)http->allowed_methods));
- evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL);
- return;
- }
-
- /* handle potential virtual hosts */
- hostname = evhttp_request_get_host(req);
- if (hostname != NULL) {
- evhttp_find_vhost(http, &http, hostname);
- }
-
- 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;
- struct evbuffer *buf;
-
- if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) {
- evhttp_connection_free(req->evcon);
- return;
- }
-
- if ((buf = evbuffer_new()) == NULL) {
- mm_free(escaped_html);
- evhttp_connection_free(req->evcon);
- return;
- }
-
- evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found");
-
- evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
-
- mm_free(escaped_html);
-
- evhttp_send_page_(req, buf);
-
- evbuffer_free(buf);
-#undef ERR_FORMAT
- }
-}
-
-/* Listener callback when a connection arrives at a server. */
-static void
-accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
-{
- struct evhttp *http = arg;
-
- evhttp_get_request(http, nfd, peer_sa, peer_socklen);
-}
-
-int
-evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)
-{
- struct evhttp_bound_socket *bound =
- evhttp_bind_socket_with_handle(http, address, port);
- if (bound == NULL)
- return (-1);
- return (0);
-}
-
-struct evhttp_bound_socket *
-evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port)
-{
- evutil_socket_t fd;
- struct evhttp_bound_socket *bound;
-
- if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
- return (NULL);
-
- if (listen(fd, 128) == -1) {
- event_sock_warn(fd, "%s: listen", __func__);
- evutil_closesocket(fd);
- return (NULL);
- }
-
- bound = evhttp_accept_socket_with_handle(http, fd);
-
- if (bound != NULL) {
- event_debug(("Bound to port %d - Awaiting connections ... ",
- port));
- return (bound);
- }
-
- return (NULL);
-}
-
-int
-evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
-{
- struct evhttp_bound_socket *bound =
- evhttp_accept_socket_with_handle(http, fd);
- if (bound == NULL)
- return (-1);
- return (0);
-}
-
-void
-evhttp_foreach_bound_socket(struct evhttp *http,
- evhttp_bound_socket_foreach_fn *function,
- void *argument)
-{
- struct evhttp_bound_socket *bound;
-
- TAILQ_FOREACH(bound, &http->sockets, next)
- function(bound, argument);
-}
-
-struct evhttp_bound_socket *
-evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
-{
- struct evhttp_bound_socket *bound;
- struct evconnlistener *listener;
- const int flags =
- LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
-
- listener = evconnlistener_new(http->base, NULL, NULL,
- flags,
- 0, /* Backlog is '0' because we already said 'listen' */
- fd);
- if (!listener)
- return (NULL);
-
- bound = evhttp_bind_listener(http, listener);
- if (!bound) {
- evconnlistener_free(listener);
- return (NULL);
- }
- return (bound);
-}
-
-struct evhttp_bound_socket *
-evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
-{
- struct evhttp_bound_socket *bound;
-
- bound = mm_malloc(sizeof(struct evhttp_bound_socket));
- if (bound == NULL)
- return (NULL);
-
- bound->listener = listener;
- TAILQ_INSERT_TAIL(&http->sockets, bound, next);
-
- evconnlistener_set_cb(listener, accept_socket_cb, http);
- return bound;
-}
-
-evutil_socket_t
-evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
-{
- return evconnlistener_get_fd(bound->listener);
-}
-
-struct evconnlistener *
-evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
-{
- return bound->listener;
-}
-
-void
-evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
-{
- TAILQ_REMOVE(&http->sockets, bound, next);
- evconnlistener_free(bound->listener);
- mm_free(bound);
-}
-
-static struct evhttp*
-evhttp_new_object(void)
-{
- struct evhttp *http = NULL;
-
- if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) {
- event_warn("%s: calloc", __func__);
- return (NULL);
- }
-
- evutil_timerclear(&http->timeout);
- evhttp_set_max_headers_size(http, EV_SIZE_MAX);
- evhttp_set_max_body_size(http, EV_SIZE_MAX);
- evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1");
- evhttp_set_allowed_methods(http,
- EVHTTP_REQ_GET |
- EVHTTP_REQ_POST |
- EVHTTP_REQ_HEAD |
- EVHTTP_REQ_PUT |
- EVHTTP_REQ_DELETE);
-
- TAILQ_INIT(&http->sockets);
- TAILQ_INIT(&http->callbacks);
- TAILQ_INIT(&http->connections);
- TAILQ_INIT(&http->virtualhosts);
- TAILQ_INIT(&http->aliases);
-
- return (http);
-}
-
-struct evhttp *
-evhttp_new(struct event_base *base)
-{
- struct evhttp *http = NULL;
-
- http = evhttp_new_object();
- if (http == NULL)
- return (NULL);
- http->base = base;
-
- return (http);
-}
-
-/*
- * Start a web server on the specified address and port.
- */
-
-struct evhttp *
-evhttp_start(const char *address, unsigned short port)
-{
- struct evhttp *http = NULL;
-
- http = evhttp_new_object();
- if (http == NULL)
- return (NULL);
- if (evhttp_bind_socket(http, address, port) == -1) {
- mm_free(http);
- return (NULL);
- }
-
- return (http);
-}
-
-void
-evhttp_free(struct evhttp* http)
-{
- struct evhttp_cb *http_cb;
- struct evhttp_connection *evcon;
- struct evhttp_bound_socket *bound;
- struct evhttp* vhost;
- struct evhttp_server_alias *alias;
-
- /* Remove the accepting part */
- while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
- TAILQ_REMOVE(&http->sockets, bound, next);
-
- evconnlistener_free(bound->listener);
-
- mm_free(bound);
- }
-
- while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
- /* evhttp_connection_free removes the connection */
- evhttp_connection_free(evcon);
- }
-
- while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
- TAILQ_REMOVE(&http->callbacks, http_cb, next);
- mm_free(http_cb->what);
- mm_free(http_cb);
- }
-
- while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
- TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
-
- evhttp_free(vhost);
- }
-
- if (http->vhost_pattern != NULL)
- mm_free(http->vhost_pattern);
-
- while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) {
- TAILQ_REMOVE(&http->aliases, alias, next);
- mm_free(alias->alias);
- mm_free(alias);
- }
-
- mm_free(http);
-}
-
-int
-evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
- struct evhttp* vhost)
-{
- /* a vhost can only be a vhost once and should not have bound sockets */
- if (vhost->vhost_pattern != NULL ||
- TAILQ_FIRST(&vhost->sockets) != NULL)
- return (-1);
-
- vhost->vhost_pattern = mm_strdup(pattern);
- if (vhost->vhost_pattern == NULL)
- return (-1);
-
- TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
-
- return (0);
-}
-
-int
-evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
-{
- if (vhost->vhost_pattern == NULL)
- return (-1);
-
- TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
-
- mm_free(vhost->vhost_pattern);
- vhost->vhost_pattern = NULL;
-
- return (0);
-}
-
-int
-evhttp_add_server_alias(struct evhttp *http, const char *alias)
-{
- struct evhttp_server_alias *evalias;
-
- evalias = mm_calloc(1, sizeof(*evalias));
- if (!evalias)
- return -1;
-
- evalias->alias = mm_strdup(alias);
- if (!evalias->alias) {
- mm_free(evalias);
- return -1;
- }
-
- TAILQ_INSERT_TAIL(&http->aliases, evalias, next);
-
- return 0;
-}
-
-int
-evhttp_remove_server_alias(struct evhttp *http, const char *alias)
-{
- struct evhttp_server_alias *evalias;
-
- TAILQ_FOREACH(evalias, &http->aliases, next) {
- if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) {
- TAILQ_REMOVE(&http->aliases, evalias, next);
- mm_free(evalias->alias);
- mm_free(evalias);
- return 0;
- }
- }
-
- return -1;
-}
-
-void
-evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
-{
- if (timeout_in_secs == -1) {
- evhttp_set_timeout_tv(http, NULL);
- } else {
- struct timeval tv;
- tv.tv_sec = timeout_in_secs;
- tv.tv_usec = 0;
- evhttp_set_timeout_tv(http, &tv);
- }
-}
-
-void
-evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
-{
- if (tv) {
- http->timeout = *tv;
- } else {
- evutil_timerclear(&http->timeout);
- }
-}
-
-void
-evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
-{
- if (max_headers_size < 0)
- http->default_max_headers_size = EV_SIZE_MAX;
- else
- http->default_max_headers_size = max_headers_size;
-}
-
-void
-evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size)
-{
- if (max_body_size < 0)
- http->default_max_body_size = EV_UINT64_MAX;
- else
- http->default_max_body_size = max_body_size;
-}
-
-void
-evhttp_set_default_content_type(struct evhttp *http,
- const char *content_type) {
- http->default_content_type = content_type;
-}
-
-void
-evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods)
-{
- http->allowed_methods = methods;
-}
-
-int
-evhttp_set_cb(struct evhttp *http, const char *uri,
- void (*cb)(struct evhttp_request *, void *), void *cbarg)
-{
- struct evhttp_cb *http_cb;
-
- TAILQ_FOREACH(http_cb, &http->callbacks, next) {
- if (strcmp(http_cb->what, uri) == 0)
- return (-1);
- }
-
- if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) {
- event_warn("%s: calloc", __func__);
- return (-2);
- }
-
- http_cb->what = mm_strdup(uri);
- if (http_cb->what == NULL) {
- event_warn("%s: strdup", __func__);
- mm_free(http_cb);
- return (-3);
- }
- http_cb->cb = cb;
- http_cb->cbarg = cbarg;
-
- TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
-
- return (0);
-}
-
-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);
- mm_free(http_cb->what);
- mm_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;
-}
-
-void
-evhttp_set_bevcb(struct evhttp *http,
- struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
-{
- http->bevcb = cb;
- http->bevcbarg = 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 = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) {
- event_warn("%s: calloc", __func__);
- goto error;
- }
-
- req->headers_size = 0;
- req->body_size = 0;
-
- req->kind = EVHTTP_RESPONSE;
- req->input_headers = mm_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 = mm_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->flags & EVHTTP_REQ_DEFER_FREE) != 0) {
- req->flags |= EVHTTP_REQ_NEEDS_FREE;
- return;
- }
-
- if (req->remote_host != NULL)
- mm_free(req->remote_host);
- if (req->uri != NULL)
- mm_free(req->uri);
- if (req->uri_elems != NULL)
- evhttp_uri_free(req->uri_elems);
- if (req->response_code_line != NULL)
- mm_free(req->response_code_line);
- if (req->host_cache != NULL)
- mm_free(req->host_cache);
-
- evhttp_clear_headers(req->input_headers);
- mm_free(req->input_headers);
-
- evhttp_clear_headers(req->output_headers);
- mm_free(req->output_headers);
-
- if (req->input_buffer != NULL)
- evbuffer_free(req->input_buffer);
-
- if (req->output_buffer != NULL)
- evbuffer_free(req->output_buffer);
-
- mm_free(req);
-}
-
-void
-evhttp_request_own(struct evhttp_request *req)
-{
- req->flags |= EVHTTP_USER_OWNED;
-}
-
-int
-evhttp_request_is_owned(struct evhttp_request *req)
-{
- return (req->flags & EVHTTP_USER_OWNED) != 0;
-}
-
-struct evhttp_connection *
-evhttp_request_get_connection(struct evhttp_request *req)
-{
- return req->evcon;
-}
-
-struct event_base *
-evhttp_connection_get_base(struct evhttp_connection *conn)
-{
- return conn->base;
-}
-
-void
-evhttp_request_set_chunked_cb(struct evhttp_request *req,
- void (*cb)(struct evhttp_request *, void *))
-{
- req->chunk_cb = cb;
-}
-
-void
-evhttp_request_set_header_cb(struct evhttp_request *req,
- int (*cb)(struct evhttp_request *, void *))
-{
- req->header_cb = cb;
-}
-
-void
-evhttp_request_set_error_cb(struct evhttp_request *req,
- void (*cb)(enum evhttp_request_error, void *))
-{
- req->error_cb = cb;
-}
-
-void
-evhttp_request_set_on_complete_cb(struct evhttp_request *req,
- void (*cb)(struct evhttp_request *, void *), void *cb_arg)
-{
- req->on_complete_cb = cb;
- req->on_complete_cb_arg = cb_arg;
-}
-
-/*
- * Allows for inspection of the request URI
- */
-
-const char *
-evhttp_request_get_uri(const struct evhttp_request *req) {
- if (req->uri == NULL)
- event_debug(("%s: request %p has no uri\n", __func__, req));
- return (req->uri);
-}
-
-const struct evhttp_uri *
-evhttp_request_get_evhttp_uri(const struct evhttp_request *req) {
- if (req->uri_elems == NULL)
- event_debug(("%s: request %p has no uri elems\n",
- __func__, req));
- return (req->uri_elems);
-}
-
-const char *
-evhttp_request_get_host(struct evhttp_request *req)
-{
- const char *host = NULL;
-
- if (req->host_cache)
- return req->host_cache;
-
- if (req->uri_elems)
- host = evhttp_uri_get_host(req->uri_elems);
- if (!host && req->input_headers) {
- const char *p;
- size_t len;
-
- host = evhttp_find_header(req->input_headers, "Host");
- /* The Host: header may include a port. Remove it here
- to be consistent with uri_elems case above. */
- if (host) {
- p = host + strlen(host) - 1;
- while (p > host && EVUTIL_ISDIGIT_(*p))
- --p;
- if (p > host && *p == ':') {
- len = p - host;
- req->host_cache = mm_malloc(len + 1);
- if (!req->host_cache) {
- event_warn("%s: malloc", __func__);
- return NULL;
- }
- memcpy(req->host_cache, host, len);
- req->host_cache[len] = '\0';
- host = req->host_cache;
- }
- }
- }
-
- return host;
-}
-
-enum evhttp_cmd_type
-evhttp_request_get_command(const struct evhttp_request *req) {
- return (req->type);
-}
-
-int
-evhttp_request_get_response_code(const struct evhttp_request *req)
-{
- return req->response_code;
-}
-
-const char *
-evhttp_request_get_response_code_line(const struct evhttp_request *req)
-{
- return req->response_code_line;
-}
-
-/** Returns the input headers */
-struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
-{
- return (req->input_headers);
-}
-
-/** Returns the output headers */
-struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
-{
- return (req->output_headers);
-}
-
-/** Returns the input buffer */
-struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
-{
- return (req->input_buffer);
-}
-
-/** Returns the output buffer */
-struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
-{
- return (req->output_buffer);
-}
-
-
-/*
- * 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,
- evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
-{
- struct evhttp_connection *evcon;
- char *hostname = NULL, *portname = NULL;
- struct bufferevent* bev = NULL;
-
- name_from_addr(sa, salen, &hostname, &portname);
- if (hostname == NULL || portname == NULL) {
- if (hostname) mm_free(hostname);
- if (portname) mm_free(portname);
- return (NULL);
- }
-
- event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
- __func__, hostname, portname, EV_SOCK_ARG(fd)));
-
- /* we need a connection object to put the http request on */
- if (http->bevcb != NULL) {
- bev = (*http->bevcb)(http->base, http->bevcbarg);
- }
- evcon = evhttp_connection_base_bufferevent_new(
- http->base, NULL, bev, hostname, atoi(portname));
- mm_free(hostname);
- mm_free(portname);
- if (evcon == NULL)
- return (NULL);
-
- evcon->max_headers_size = http->default_max_headers_size;
- evcon->max_body_size = http->default_max_body_size;
-
- evcon->flags |= EVHTTP_CON_INCOMING;
- evcon->state = EVCON_READING_FIRSTLINE;
-
- evcon->fd = fd;
-
- bufferevent_enable(evcon->bufev, EV_READ);
- bufferevent_disable(evcon->bufev, EV_WRITE);
- bufferevent_setfd(evcon->bufev, 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);
-
- if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
- event_warn("%s: strdup", __func__);
- evhttp_request_free(req);
- return (-1);
- }
- req->remote_port = evcon->port;
-
- req->evcon = evcon; /* the request ends up owning the connection */
- req->flags |= EVHTTP_REQ_OWN_CONNECTION;
-
- /* We did not present the request to the user user yet, so treat it as
- * if the user was done with the request. This allows us to free the
- * request on a persistent connection if the client drops it without
- * sending a request.
- */
- req->userdone = 1;
-
- TAILQ_INSERT_TAIL(&evcon->requests, req, next);
-
- req->kind = EVHTTP_REQUEST;
-
-
- evhttp_start_read_(evcon);
-
- return (0);
-}
-
-static void
-evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
- struct sockaddr *sa, ev_socklen_t salen)
-{
- struct evhttp_connection *evcon;
-
- evcon = evhttp_get_request_connection(http, fd, sa, salen);
- if (evcon == NULL) {
- event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
- __func__, EV_SOCK_ARG(fd));
- evutil_closesocket(fd);
- return;
- }
-
- /* the timeout can be used by the server to close idle connections */
- if (evutil_timerisset(&http->timeout))
- evhttp_connection_set_timeout_tv(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.
- */
-
-static void
-name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
- char **phost, char **pport)
-{
- char ntop[NI_MAXHOST];
- char strport[NI_MAXSERV];
- int ni_result;
-
-#ifdef EVENT__HAVE_GETNAMEINFO
- ni_result = getnameinfo(sa, salen,
- ntop, sizeof(ntop), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV);
-
- if (ni_result != 0) {
-#ifdef EAI_SYSTEM
- /* Windows doesn't have an EAI_SYSTEM. */
- if (ni_result == EAI_SYSTEM)
- event_err(1, "getnameinfo failed");
- else
-#endif
- event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
- return;
- }
-#else
- ni_result = fake_getnameinfo(sa, salen,
- ntop, sizeof(ntop), strport, sizeof(strport),
- NI_NUMERICHOST|NI_NUMERICSERV);
- if (ni_result != 0)
- return;
-#endif
-
- *phost = mm_strdup(ntop);
- *pport = mm_strdup(strport);
-}
-
-/* Create a non-blocking socket and bind it */
-/* todo: rename this function */
-static evutil_socket_t
-bind_socket_ai(struct evutil_addrinfo *ai, int reuse)
-{
- evutil_socket_t fd;
-
- int on = 1, r;
- int serrno;
-
- /* Create listen socket */
- fd = evutil_socket_(ai ? ai->ai_family : AF_INET,
- SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
- if (fd == -1) {
- event_sock_warn(-1, "socket");
- return (-1);
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
- goto out;
- if (reuse) {
- if (evutil_make_listen_socket_reuseable(fd) < 0)
- goto out;
- }
-
- if (ai != NULL) {
- r = bind(fd, ai->ai_addr, (ev_socklen_t)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 evutil_addrinfo *
-make_addrinfo(const char *address, ev_uint16_t port)
-{
- struct evutil_addrinfo *ai = NULL;
-
- struct evutil_addrinfo hints;
- char strport[NI_MAXSERV];
- int ai_result;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- /* turn NULL hostname into INADDR_ANY, and skip looking up any address
- * types we don't have an interface to connect to. */
- hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
- evutil_snprintf(strport, sizeof(strport), "%d", port);
- if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
- != 0) {
- if (ai_result == EVUTIL_EAI_SYSTEM)
- event_warn("getaddrinfo");
- else
- event_warnx("getaddrinfo: %s",
- evutil_gai_strerror(ai_result));
- return (NULL);
- }
-
- return (ai);
-}
-
-static evutil_socket_t
-bind_socket(const char *address, ev_uint16_t port, int reuse)
-{
- evutil_socket_t fd;
- struct evutil_addrinfo *aitop = NULL;
-
- /* just create an unbound socket */
- if (address == NULL && port == 0)
- return bind_socket_ai(NULL, 0);
-
- aitop = make_addrinfo(address, port);
-
- if (aitop == NULL)
- return (-1);
-
- fd = bind_socket_ai(aitop, reuse);
-
- evutil_freeaddrinfo(aitop);
-
- return (fd);
-}
-
-struct evhttp_uri {
- unsigned flags;
- char *scheme; /* scheme; e.g http, ftp etc */
- char *userinfo; /* userinfo (typically username:pass), or NULL */
- char *host; /* hostname, IP address, or NULL */
- int port; /* port, or zero */
- char *path; /* path, or "". */
- char *query; /* query, or NULL */
- char *fragment; /* fragment or NULL */
-};
-
-struct evhttp_uri *
-evhttp_uri_new(void)
-{
- struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1);
- if (uri)
- uri->port = -1;
- return uri;
-}
-
-void
-evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags)
-{
- uri->flags = flags;
-}
-
-/* Return true if the string starting at s and ending immediately before eos
- * is a valid URI scheme according to RFC3986
- */
-static int
-scheme_ok(const char *s, const char *eos)
-{
- /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
- EVUTIL_ASSERT(eos >= s);
- if (s == eos)
- return 0;
- if (!EVUTIL_ISALPHA_(*s))
- return 0;
- while (++s < eos) {
- if (! EVUTIL_ISALNUM_(*s) &&
- *s != '+' && *s != '-' && *s != '.')
- return 0;
- }
- return 1;
-}
-
-#define SUBDELIMS "!$&'()*+,;="
-
-/* Return true iff [s..eos) is a valid userinfo */
-static int
-userinfo_ok(const char *s, const char *eos)
-{
- while (s < eos) {
- if (CHAR_IS_UNRESERVED(*s) ||
- strchr(SUBDELIMS, *s) ||
- *s == ':')
- ++s;
- else if (*s == '%' && s+2 < eos &&
- EVUTIL_ISXDIGIT_(s[1]) &&
- EVUTIL_ISXDIGIT_(s[2]))
- s += 3;
- else
- return 0;
- }
- return 1;
-}
-
-static int
-regname_ok(const char *s, const char *eos)
-{
- while (s && s<eos) {
- if (CHAR_IS_UNRESERVED(*s) ||
- strchr(SUBDELIMS, *s))
- ++s;
- else if (*s == '%' &&
- EVUTIL_ISXDIGIT_(s[1]) &&
- EVUTIL_ISXDIGIT_(s[2]))
- s += 3;
- else
- return 0;
- }
- return 1;
-}
-
-static int
-parse_port(const char *s, const char *eos)
-{
- int portnum = 0;
- while (s < eos) {
- if (! EVUTIL_ISDIGIT_(*s))
- return -1;
- portnum = (portnum * 10) + (*s - '0');
- if (portnum < 0)
- return -1;
- if (portnum > 65535)
- return -1;
- ++s;
- }
- return portnum;
-}
-
-/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */
-static int
-bracket_addr_ok(const char *s, const char *eos)
-{
- if (s + 3 > eos || *s != '[' || *(eos-1) != ']')
- return 0;
- if (s[1] == 'v') {
- /* IPvFuture, or junk.
- "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
- */
- s += 2; /* skip [v */
- --eos;
- if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/
- return 0;
- while (s < eos && *s != '.') {
- if (EVUTIL_ISXDIGIT_(*s))
- ++s;
- else
- return 0;
- }
- if (*s != '.')
- return 0;
- ++s;
- while (s < eos) {
- if (CHAR_IS_UNRESERVED(*s) ||
- strchr(SUBDELIMS, *s) ||
- *s == ':')
- ++s;
- else
- return 0;
- }
- return 2;
- } else {
- /* IPv6, or junk */
- char buf[64];
- ev_ssize_t n_chars = eos-s-2;
- struct in6_addr in6;
- if (n_chars >= 64) /* way too long */
- return 0;
- memcpy(buf, s+1, n_chars);
- buf[n_chars]='\0';
- return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0;
- }
-}
-
-static int
-parse_authority(struct evhttp_uri *uri, char *s, char *eos)
-{
- char *cp, *port;
- EVUTIL_ASSERT(eos);
- if (eos == s) {
- uri->host = mm_strdup("");
- if (uri->host == NULL) {
- event_warn("%s: strdup", __func__);
- return -1;
- }
- return 0;
- }
-
- /* Optionally, we start with "userinfo@" */
-
- cp = strchr(s, '@');
- if (cp && cp < eos) {
- if (! userinfo_ok(s,cp))
- return -1;
- *cp++ = '\0';
- uri->userinfo = mm_strdup(s);
- if (uri->userinfo == NULL) {
- event_warn("%s: strdup", __func__);
- return -1;
- }
- } else {
- cp = s;
- }
- /* Optionally, we end with ":port" */
- for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
- ;
- if (port >= cp && *port == ':') {
- if (port+1 == eos) /* Leave port unspecified; the RFC allows a
- * nil port */
- uri->port = -1;
- else if ((uri->port = parse_port(port+1, eos))<0)
- return -1;
- eos = port;
- }
- /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
- * an IP-Literal, or a reg-name */
- EVUTIL_ASSERT(eos >= cp);
- if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
- /* IPv6address, IP-Literal, or junk. */
- if (! bracket_addr_ok(cp, eos))
- return -1;
- } else {
- /* Make sure the host part is ok. */
- if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
- return -1;
- }
- uri->host = mm_malloc(eos-cp+1);
- if (uri->host == NULL) {
- event_warn("%s: malloc", __func__);
- return -1;
- }
- memcpy(uri->host, cp, eos-cp);
- uri->host[eos-cp] = '\0';
- return 0;
-
-}
-
-static char *
-end_of_authority(char *cp)
-{
- while (*cp) {
- if (*cp == '?' || *cp == '#' || *cp == '/')
- return cp;
- ++cp;
- }
- return cp;
-}
-
-enum uri_part {
- PART_PATH,
- PART_QUERY,
- PART_FRAGMENT
-};
-
-/* Return the character after the longest prefix of 'cp' that matches...
- * *pchar / "/" if allow_qchars is false, or
- * *(pchar / "/" / "?") if allow_qchars is true.
- */
-static char *
-end_of_path(char *cp, enum uri_part part, unsigned flags)
-{
- if (flags & EVHTTP_URI_NONCONFORMANT) {
- /* If NONCONFORMANT:
- * Path is everything up to a # or ? or nul.
- * Query is everything up a # or nul
- * Fragment is everything up to a nul.
- */
- switch (part) {
- case PART_PATH:
- while (*cp && *cp != '#' && *cp != '?')
- ++cp;
- break;
- case PART_QUERY:
- while (*cp && *cp != '#')
- ++cp;
- break;
- case PART_FRAGMENT:
- cp += strlen(cp);
- break;
- };
- return cp;
- }
-
- while (*cp) {
- if (CHAR_IS_UNRESERVED(*cp) ||
- strchr(SUBDELIMS, *cp) ||
- *cp == ':' || *cp == '@' || *cp == '/')
- ++cp;
- else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) &&
- EVUTIL_ISXDIGIT_(cp[2]))
- cp += 3;
- else if (*cp == '?' && part != PART_PATH)
- ++cp;
- else
- return cp;
- }
- return cp;
-}
-
-static int
-path_matches_noscheme(const char *cp)
-{
- while (*cp) {
- if (*cp == ':')
- return 0;
- else if (*cp == '/')
- return 1;
- ++cp;
- }
- return 1;
-}
-
-struct evhttp_uri *
-evhttp_uri_parse(const char *source_uri)
-{
- return evhttp_uri_parse_with_flags(source_uri, 0);
-}
-
-struct evhttp_uri *
-evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
-{
- char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL;
- char *path = NULL, *fragment = NULL;
- int got_authority = 0;
-
- struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
- if (uri == NULL) {
- event_warn("%s: calloc", __func__);
- goto err;
- }
- uri->port = -1;
- uri->flags = flags;
-
- readbuf = mm_strdup(source_uri);
- if (readbuf == NULL) {
- event_warn("%s: strdup", __func__);
- goto err;
- }
-
- readp = readbuf;
- token = NULL;
-
- /* We try to follow RFC3986 here as much as we can, and match
- the productions
-
- URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
-
- relative-ref = relative-part [ "?" query ] [ "#" fragment ]
- */
-
- /* 1. scheme: */
- token = strchr(readp, ':');
- if (token && scheme_ok(readp,token)) {
- *token = '\0';
- uri->scheme = mm_strdup(readp);
- if (uri->scheme == NULL) {
- event_warn("%s: strdup", __func__);
- goto err;
- }
- readp = token+1; /* eat : */
- }
-
- /* 2. Optionally, "//" then an 'authority' part. */
- if (readp[0]=='/' && readp[1] == '/') {
- char *authority;
- readp += 2;
- authority = readp;
- path = end_of_authority(readp);
- if (parse_authority(uri, authority, path) < 0)
- goto err;
- readp = path;
- got_authority = 1;
- }
-
- /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty
- */
- path = readp;
- readp = end_of_path(path, PART_PATH, flags);
-
- /* Query */
- if (*readp == '?') {
- *readp = '\0';
- ++readp;
- query = readp;
- readp = end_of_path(readp, PART_QUERY, flags);
- }
- /* fragment */
- if (*readp == '#') {
- *readp = '\0';
- ++readp;
- fragment = readp;
- readp = end_of_path(readp, PART_FRAGMENT, flags);
- }
- if (*readp != '\0') {
- goto err;
- }
-
- /* These next two cases may be unreachable; I'm leaving them
- * in to be defensive. */
- /* If you didn't get an authority, the path can't begin with "//" */
- if (!got_authority && path[0]=='/' && path[1]=='/')
- goto err;
- /* If you did get an authority, the path must begin with "/" or be
- * empty. */
- if (got_authority && path[0] != '/' && path[0] != '\0')
- goto err;
- /* (End of maybe-unreachable cases) */
-
- /* If there was no scheme, the first part of the path (if any) must
- * have no colon in it. */
- if (! uri->scheme && !path_matches_noscheme(path))
- goto err;
-
- EVUTIL_ASSERT(path);
- uri->path = mm_strdup(path);
- if (uri->path == NULL) {
- event_warn("%s: strdup", __func__);
- goto err;
- }
-
- if (query) {
- uri->query = mm_strdup(query);
- if (uri->query == NULL) {
- event_warn("%s: strdup", __func__);
- goto err;
- }
- }
- if (fragment) {
- uri->fragment = mm_strdup(fragment);
- if (uri->fragment == NULL) {
- event_warn("%s: strdup", __func__);
- goto err;
- }
- }
-
- mm_free(readbuf);
-
- return uri;
-err:
- if (uri)
- evhttp_uri_free(uri);
- if (readbuf)
- mm_free(readbuf);
- return NULL;
-}
-
-void
-evhttp_uri_free(struct evhttp_uri *uri)
-{
-#define URI_FREE_STR_(f) \
- if (uri->f) { \
- mm_free(uri->f); \
- }
-
- URI_FREE_STR_(scheme);
- URI_FREE_STR_(userinfo);
- URI_FREE_STR_(host);
- URI_FREE_STR_(path);
- URI_FREE_STR_(query);
- URI_FREE_STR_(fragment);
-
- mm_free(uri);
-#undef URI_FREE_STR_
-}
-
-char *
-evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
-{
- struct evbuffer *tmp = 0;
- size_t joined_size = 0;
- char *output = NULL;
-
-#define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f))
-
- if (!uri || !buf || !limit)
- return NULL;
-
- tmp = evbuffer_new();
- if (!tmp)
- return NULL;
-
- if (uri->scheme) {
- URI_ADD_(scheme);
- evbuffer_add(tmp, ":", 1);
- }
- if (uri->host) {
- evbuffer_add(tmp, "//", 2);
- if (uri->userinfo)
- evbuffer_add_printf(tmp,"%s@", uri->userinfo);
- URI_ADD_(host);
- if (uri->port >= 0)
- evbuffer_add_printf(tmp,":%d", uri->port);
-
- if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0')
- goto err;
- }
-
- if (uri->path)
- URI_ADD_(path);
-
- if (uri->query) {
- evbuffer_add(tmp, "?", 1);
- URI_ADD_(query);
- }
-
- if (uri->fragment) {
- evbuffer_add(tmp, "#", 1);
- URI_ADD_(fragment);
- }
-
- evbuffer_add(tmp, "\0", 1); /* NUL */
-
- joined_size = evbuffer_get_length(tmp);
-
- if (joined_size > limit) {
- /* It doesn't fit. */
- evbuffer_free(tmp);
- return NULL;
- }
- evbuffer_remove(tmp, buf, joined_size);
-
- output = buf;
-err:
- evbuffer_free(tmp);
-
- return output;
-#undef URI_ADD_
-}
-
-const char *
-evhttp_uri_get_scheme(const struct evhttp_uri *uri)
-{
- return uri->scheme;
-}
-const char *
-evhttp_uri_get_userinfo(const struct evhttp_uri *uri)
-{
- return uri->userinfo;
-}
-const char *
-evhttp_uri_get_host(const struct evhttp_uri *uri)
-{
- return uri->host;
-}
-int
-evhttp_uri_get_port(const struct evhttp_uri *uri)
-{
- return uri->port;
-}
-const char *
-evhttp_uri_get_path(const struct evhttp_uri *uri)
-{
- return uri->path;
-}
-const char *
-evhttp_uri_get_query(const struct evhttp_uri *uri)
-{
- return uri->query;
-}
-const char *
-evhttp_uri_get_fragment(const struct evhttp_uri *uri)
-{
- return uri->fragment;
-}
-
-#define URI_SET_STR_(f) do { \
- if (uri->f) \
- mm_free(uri->f); \
- if (f) { \
- if ((uri->f = mm_strdup(f)) == NULL) { \
- event_warn("%s: strdup()", __func__); \
- return -1; \
- } \
- } else { \
- uri->f = NULL; \
- } \
- } while(0)
-
-int
-evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme)
-{
- if (scheme && !scheme_ok(scheme, scheme+strlen(scheme)))
- return -1;
-
- URI_SET_STR_(scheme);
- return 0;
-}
-int
-evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
-{
- if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo)))
- return -1;
- URI_SET_STR_(userinfo);
- return 0;
-}
-int
-evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
-{
- if (host) {
- if (host[0] == '[') {
- if (! bracket_addr_ok(host, host+strlen(host)))
- return -1;
- } else {
- if (! regname_ok(host, host+strlen(host)))
- return -1;
- }
- }
-
- URI_SET_STR_(host);
- return 0;
-}
-int
-evhttp_uri_set_port(struct evhttp_uri *uri, int port)
-{
- if (port < -1)
- return -1;
- uri->port = port;
- return 0;
-}
-#define end_of_cpath(cp,p,f) \
- ((const char*)(end_of_path(((char*)(cp)), (p), (f))))
-
-int
-evhttp_uri_set_path(struct evhttp_uri *uri, const char *path)
-{
- if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path))
- return -1;
-
- URI_SET_STR_(path);
- return 0;
-}
-int
-evhttp_uri_set_query(struct evhttp_uri *uri, const char *query)
-{
- if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query))
- return -1;
- URI_SET_STR_(query);
- return 0;
-}
-int
-evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment)
-{
- if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment))
- return -1;
- URI_SET_STR_(fragment);
- return 0;
-}
diff --git a/libs/libevent/src/iocp-internal.h b/libs/libevent/src/iocp-internal.h
deleted file mode 100644
index 93dbe2b1a4..0000000000
--- a/libs/libevent/src/iocp-internal.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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 IOCP_INTERNAL_H_INCLUDED_
-#define IOCP_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct event_overlapped;
-struct event_iocp_port;
-struct evbuffer;
-typedef void (*iocp_callback)(struct event_overlapped *, ev_uintptr_t, ev_ssize_t, int success);
-
-/* This whole file is actually win32 only. We wrap the structures in a win32
- * ifdef so that we can test-compile code that uses these interfaces on
- * non-win32 platforms. */
-#ifdef _WIN32
-
-/**
- Internal use only. Wraps an OVERLAPPED that we're using for libevent
- functionality. Whenever an event_iocp_port gets an event for a given
- OVERLAPPED*, it upcasts the pointer to an event_overlapped, and calls the
- iocp_callback function with the event_overlapped, the iocp key, and the
- number of bytes transferred as arguments.
- */
-struct event_overlapped {
- OVERLAPPED overlapped;
- iocp_callback cb;
-};
-
-/* Mingw's headers don't define LPFN_ACCEPTEX. */
-
-typedef BOOL (WINAPI *AcceptExPtr)(SOCKET, SOCKET, PVOID, DWORD, DWORD, DWORD, LPDWORD, LPOVERLAPPED);
-typedef BOOL (WINAPI *ConnectExPtr)(SOCKET, const struct sockaddr *, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED);
-typedef void (WINAPI *GetAcceptExSockaddrsPtr)(PVOID, DWORD, DWORD, DWORD, LPSOCKADDR *, LPINT, LPSOCKADDR *, LPINT);
-
-/** Internal use only. Holds pointers to functions that only some versions of
- Windows provide.
- */
-struct win32_extension_fns {
- AcceptExPtr AcceptEx;
- ConnectExPtr ConnectEx;
- GetAcceptExSockaddrsPtr GetAcceptExSockaddrs;
-};
-
-/**
- Internal use only. Stores a Windows IO Completion port, along with
- related data.
- */
-struct event_iocp_port {
- /** The port itself */
- HANDLE port;
- /* A lock to cover internal structures. */
- CRITICAL_SECTION lock;
- /** Number of threads ever open on the port. */
- short n_threads;
- /** True iff we're shutting down all the threads on this port */
- short shutdown;
- /** How often the threads on this port check for shutdown and other
- * conditions */
- long ms;
- /* The threads that are waiting for events. */
- HANDLE *threads;
- /** Number of threads currently open on this port. */
- short n_live_threads;
- /** A semaphore to signal when we are done shutting down. */
- HANDLE *shutdownSemaphore;
-};
-
-const struct win32_extension_fns *event_get_win32_extension_fns_(void);
-#else
-/* Dummy definition so we can test-compile more things on unix. */
-struct event_overlapped {
- iocp_callback cb;
-};
-#endif
-
-/** Initialize the fields in an event_overlapped.
-
- @param overlapped The struct event_overlapped to initialize
- @param cb The callback that should be invoked once the IO operation has
- finished.
- */
-void event_overlapped_init_(struct event_overlapped *, iocp_callback cb);
-
-/** Allocate and return a new evbuffer that supports overlapped IO on a given
- socket. The socket must be associated with an IO completion port using
- event_iocp_port_associate_.
-*/
-struct evbuffer *evbuffer_overlapped_new_(evutil_socket_t fd);
-
-/** XXXX Document (nickm) */
-evutil_socket_t evbuffer_overlapped_get_fd_(struct evbuffer *buf);
-
-void evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd);
-
-/** Start reading data onto the end of an overlapped evbuffer.
-
- An evbuffer can only have one read pending at a time. While the read
- is in progress, no other data may be added to the end of the buffer.
- The buffer must be created with event_overlapped_init_().
- evbuffer_commit_read_() must be called in the completion callback.
-
- @param buf The buffer to read onto
- @param n The number of bytes to try to read.
- @param ol Overlapped object with associated completion callback.
- @return 0 on success, -1 on error.
- */
-int evbuffer_launch_read_(struct evbuffer *buf, size_t n, struct event_overlapped *ol);
-
-/** Start writing data from the start of an evbuffer.
-
- An evbuffer can only have one write pending at a time. While the write is
- in progress, no other data may be removed from the front of the buffer.
- The buffer must be created with event_overlapped_init_().
- evbuffer_commit_write_() must be called in the completion callback.
-
- @param buf The buffer to read onto
- @param n The number of bytes to try to read.
- @param ol Overlapped object with associated completion callback.
- @return 0 on success, -1 on error.
- */
-int evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t n, struct event_overlapped *ol);
-
-/** XXX document */
-void evbuffer_commit_read_(struct evbuffer *, ev_ssize_t);
-void evbuffer_commit_write_(struct evbuffer *, ev_ssize_t);
-
-/** Create an IOCP, and launch its worker threads. Internal use only.
-
- This interface is unstable, and will change.
- */
-struct event_iocp_port *event_iocp_port_launch_(int n_cpus);
-
-/** Associate a file descriptor with an iocp, such that overlapped IO on the
- fd will happen on one of the iocp's worker threads.
-*/
-int event_iocp_port_associate_(struct event_iocp_port *port, evutil_socket_t fd,
- ev_uintptr_t key);
-
-/** Tell all threads serving an iocp to stop. Wait for up to waitMsec for all
- the threads to finish whatever they're doing. If waitMsec is -1, wait
- as long as required. If all the threads are done, free the port and return
- 0. Otherwise, return -1. If you get a -1 return value, it is safe to call
- this function again.
-*/
-int event_iocp_shutdown_(struct event_iocp_port *port, long waitMsec);
-
-/* FIXME document. */
-int event_iocp_activate_overlapped_(struct event_iocp_port *port,
- struct event_overlapped *o,
- ev_uintptr_t key, ev_uint32_t n_bytes);
-
-struct event_base;
-/* FIXME document. */
-struct event_iocp_port *event_base_get_iocp_(struct event_base *base);
-
-/* FIXME document. */
-int event_base_start_iocp_(struct event_base *base, int n_cpus);
-void event_base_stop_iocp_(struct event_base *base);
-
-/* FIXME document. */
-struct bufferevent *bufferevent_async_new_(struct event_base *base,
- evutil_socket_t fd, int options);
-
-/* FIXME document. */
-void bufferevent_async_set_connected_(struct bufferevent *bev);
-int bufferevent_async_can_connect_(struct bufferevent *bev);
-int bufferevent_async_connect_(struct bufferevent *bev, evutil_socket_t fd,
- const struct sockaddr *sa, int socklen);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/libevent/src/ipv6-internal.h b/libs/libevent/src/ipv6-internal.h
deleted file mode 100644
index 0c207377b8..0000000000
--- a/libs/libevent/src/ipv6-internal.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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.
- */
-
-/* Internal use only: Fake IPv6 structures and values on platforms that
- * do not have them */
-
-#ifndef IPV6_INTERNAL_H_INCLUDED_
-#define IPV6_INTERNAL_H_INCLUDED_
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include "event2/util.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** @file ipv6-internal.h
- *
- * Replacement types and functions for platforms that don't support ipv6
- * properly.
- */
-
-#ifndef EVENT__HAVE_STRUCT_IN6_ADDR
-struct in6_addr {
- ev_uint8_t s6_addr[16];
-};
-#endif
-
-#ifndef EVENT__HAVE_SA_FAMILY_T
-typedef int sa_family_t;
-#endif
-
-#ifndef EVENT__HAVE_STRUCT_SOCKADDR_IN6
-struct sockaddr_in6 {
- /* This will fail if we find a struct sockaddr that doesn't have
- * sa_family as the first element. */
- sa_family_t sin6_family;
- ev_uint16_t sin6_port;
- struct in6_addr sin6_addr;
-};
-#endif
-
-#ifndef AF_INET6
-#define AF_INET6 3333
-#endif
-#ifndef PF_INET6
-#define PF_INET6 AF_INET6
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/libevent/src/listener.c b/libs/libevent/src/listener.c
deleted file mode 100644
index 2af14e3a7b..0000000000
--- a/libs/libevent/src/listener.c
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifdef _WIN32
-#ifndef _WIN32_WINNT
-/* Minimum required for InitializeCriticalSectionAndSpinCount */
-#define _WIN32_WINNT 0x0403
-#endif
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <mswsock.h>
-#endif
-#include <errno.h>
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef EVENT__HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "event2/listener.h"
-#include "event2/util.h"
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "mm-internal.h"
-#include "util-internal.h"
-#include "log-internal.h"
-#include "evthread-internal.h"
-#ifdef _WIN32
-#include "iocp-internal.h"
-#include "defer-internal.h"
-#include "event-internal.h"
-#endif
-
-struct evconnlistener_ops {
- int (*enable)(struct evconnlistener *);
- int (*disable)(struct evconnlistener *);
- void (*destroy)(struct evconnlistener *);
- void (*shutdown)(struct evconnlistener *);
- evutil_socket_t (*getfd)(struct evconnlistener *);
- struct event_base *(*getbase)(struct evconnlistener *);
-};
-
-struct evconnlistener {
- const struct evconnlistener_ops *ops;
- void *lock;
- evconnlistener_cb cb;
- evconnlistener_errorcb errorcb;
- void *user_data;
- unsigned flags;
- short refcnt;
- int accept4_flags;
- unsigned enabled : 1;
-};
-
-struct evconnlistener_event {
- struct evconnlistener base;
- struct event listener;
-};
-
-#ifdef _WIN32
-struct evconnlistener_iocp {
- struct evconnlistener base;
- evutil_socket_t fd;
- struct event_base *event_base;
- struct event_iocp_port *port;
- short n_accepting;
- unsigned shutting_down : 1;
- unsigned event_added : 1;
- struct accepting_socket **accepting;
-};
-#endif
-
-#define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0)
-#define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0)
-
-struct evconnlistener *
-evconnlistener_new_async(struct event_base *base,
- evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
- evutil_socket_t fd); /* XXXX export this? */
-
-static int event_listener_enable(struct evconnlistener *);
-static int event_listener_disable(struct evconnlistener *);
-static void event_listener_destroy(struct evconnlistener *);
-static evutil_socket_t event_listener_getfd(struct evconnlistener *);
-static struct event_base *event_listener_getbase(struct evconnlistener *);
-
-#if 0
-static void
-listener_incref_and_lock(struct evconnlistener *listener)
-{
- LOCK(listener);
- ++listener->refcnt;
-}
-#endif
-
-static int
-listener_decref_and_unlock(struct evconnlistener *listener)
-{
- int refcnt = --listener->refcnt;
- if (refcnt == 0) {
- listener->ops->destroy(listener);
- UNLOCK(listener);
- EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- mm_free(listener);
- return 1;
- } else {
- UNLOCK(listener);
- return 0;
- }
-}
-
-static const struct evconnlistener_ops evconnlistener_event_ops = {
- event_listener_enable,
- event_listener_disable,
- event_listener_destroy,
- NULL, /* shutdown */
- event_listener_getfd,
- event_listener_getbase
-};
-
-static void listener_read_cb(evutil_socket_t, short, void *);
-
-struct evconnlistener *
-evconnlistener_new(struct event_base *base,
- evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
- evutil_socket_t fd)
-{
- struct evconnlistener_event *lev;
-
-#ifdef _WIN32
- if (base && event_base_get_iocp_(base)) {
- const struct win32_extension_fns *ext =
- event_get_win32_extension_fns_();
- if (ext->AcceptEx && ext->GetAcceptExSockaddrs)
- return evconnlistener_new_async(base, cb, ptr, flags,
- backlog, fd);
- }
-#endif
-
- if (backlog > 0) {
- if (listen(fd, backlog) < 0)
- return NULL;
- } else if (backlog < 0) {
- if (listen(fd, 128) < 0)
- return NULL;
- }
-
- lev = mm_calloc(1, sizeof(struct evconnlistener_event));
- if (!lev)
- return NULL;
-
- lev->base.ops = &evconnlistener_event_ops;
- lev->base.cb = cb;
- lev->base.user_data = ptr;
- lev->base.flags = flags;
- lev->base.refcnt = 1;
-
- lev->base.accept4_flags = 0;
- if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
- lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK;
- if (flags & LEV_OPT_CLOSE_ON_EXEC)
- lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC;
-
- if (flags & LEV_OPT_THREADSAFE) {
- EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
- }
-
- event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
- listener_read_cb, lev);
-
- if (!(flags & LEV_OPT_DISABLED))
- evconnlistener_enable(&lev->base);
-
- return &lev->base;
-}
-
-struct evconnlistener *
-evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
- void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
- int socklen)
-{
- struct evconnlistener *listener;
- evutil_socket_t fd;
- int on = 1;
- int family = sa ? sa->sa_family : AF_UNSPEC;
- int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
-
- if (backlog == 0)
- return NULL;
-
- if (flags & LEV_OPT_CLOSE_ON_EXEC)
- socktype |= EVUTIL_SOCK_CLOEXEC;
-
- fd = evutil_socket_(family, socktype, 0);
- if (fd == -1)
- return NULL;
-
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
- goto err;
-
- if (flags & LEV_OPT_REUSEABLE) {
- if (evutil_make_listen_socket_reuseable(fd) < 0)
- goto err;
- }
-
- if (flags & LEV_OPT_REUSEABLE_PORT) {
- if (evutil_make_listen_socket_reuseable_port(fd) < 0)
- goto err;
- }
-
- if (flags & LEV_OPT_DEFERRED_ACCEPT) {
- if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
- goto err;
- }
-
- if (sa) {
- if (bind(fd, sa, socklen)<0)
- goto err;
- }
-
- listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
- if (!listener)
- goto err;
-
- return listener;
-err:
- evutil_closesocket(fd);
- return NULL;
-}
-
-void
-evconnlistener_free(struct evconnlistener *lev)
-{
- LOCK(lev);
- lev->cb = NULL;
- lev->errorcb = NULL;
- if (lev->ops->shutdown)
- lev->ops->shutdown(lev);
- listener_decref_and_unlock(lev);
-}
-
-static void
-event_listener_destroy(struct evconnlistener *lev)
-{
- struct evconnlistener_event *lev_e =
- EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
-
- event_del(&lev_e->listener);
- if (lev->flags & LEV_OPT_CLOSE_ON_FREE)
- evutil_closesocket(event_get_fd(&lev_e->listener));
- event_debug_unassign(&lev_e->listener);
-}
-
-int
-evconnlistener_enable(struct evconnlistener *lev)
-{
- int r;
- LOCK(lev);
- lev->enabled = 1;
- if (lev->cb)
- r = lev->ops->enable(lev);
- else
- r = 0;
- UNLOCK(lev);
- return r;
-}
-
-int
-evconnlistener_disable(struct evconnlistener *lev)
-{
- int r;
- LOCK(lev);
- lev->enabled = 0;
- r = lev->ops->disable(lev);
- UNLOCK(lev);
- return r;
-}
-
-static int
-event_listener_enable(struct evconnlistener *lev)
-{
- struct evconnlistener_event *lev_e =
- EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
- return event_add(&lev_e->listener, NULL);
-}
-
-static int
-event_listener_disable(struct evconnlistener *lev)
-{
- struct evconnlistener_event *lev_e =
- EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
- return event_del(&lev_e->listener);
-}
-
-evutil_socket_t
-evconnlistener_get_fd(struct evconnlistener *lev)
-{
- evutil_socket_t fd;
- LOCK(lev);
- fd = lev->ops->getfd(lev);
- UNLOCK(lev);
- return fd;
-}
-
-static evutil_socket_t
-event_listener_getfd(struct evconnlistener *lev)
-{
- struct evconnlistener_event *lev_e =
- EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
- return event_get_fd(&lev_e->listener);
-}
-
-struct event_base *
-evconnlistener_get_base(struct evconnlistener *lev)
-{
- struct event_base *base;
- LOCK(lev);
- base = lev->ops->getbase(lev);
- UNLOCK(lev);
- return base;
-}
-
-static struct event_base *
-event_listener_getbase(struct evconnlistener *lev)
-{
- struct evconnlistener_event *lev_e =
- EVUTIL_UPCAST(lev, struct evconnlistener_event, base);
- return event_get_base(&lev_e->listener);
-}
-
-void
-evconnlistener_set_cb(struct evconnlistener *lev,
- evconnlistener_cb cb, void *arg)
-{
- int enable = 0;
- LOCK(lev);
- if (lev->enabled && !lev->cb)
- enable = 1;
- lev->cb = cb;
- lev->user_data = arg;
- if (enable)
- evconnlistener_enable(lev);
- UNLOCK(lev);
-}
-
-void
-evconnlistener_set_error_cb(struct evconnlistener *lev,
- evconnlistener_errorcb errorcb)
-{
- LOCK(lev);
- lev->errorcb = errorcb;
- UNLOCK(lev);
-}
-
-static void
-listener_read_cb(evutil_socket_t fd, short what, void *p)
-{
- struct evconnlistener *lev = p;
- int err;
- evconnlistener_cb cb;
- evconnlistener_errorcb errorcb;
- void *user_data;
- LOCK(lev);
- while (1) {
- struct sockaddr_storage ss;
- ev_socklen_t socklen = sizeof(ss);
- evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags);
- if (new_fd < 0)
- break;
- if (socklen == 0) {
- /* This can happen with some older linux kernels in
- * response to nmap. */
- evutil_closesocket(new_fd);
- continue;
- }
-
- if (lev->cb == NULL) {
- evutil_closesocket(new_fd);
- UNLOCK(lev);
- return;
- }
- ++lev->refcnt;
- cb = lev->cb;
- user_data = lev->user_data;
- UNLOCK(lev);
- cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen,
- user_data);
- LOCK(lev);
- if (lev->refcnt == 1) {
- int freed = listener_decref_and_unlock(lev);
- EVUTIL_ASSERT(freed);
-
- evutil_closesocket(new_fd);
- return;
- }
- --lev->refcnt;
- }
- err = evutil_socket_geterror(fd);
- if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) {
- UNLOCK(lev);
- return;
- }
- if (lev->errorcb != NULL) {
- ++lev->refcnt;
- errorcb = lev->errorcb;
- user_data = lev->user_data;
- UNLOCK(lev);
- errorcb(lev, user_data);
- LOCK(lev);
- listener_decref_and_unlock(lev);
- } else {
- event_sock_warn(fd, "Error from accept() call");
- }
-}
-
-#ifdef _WIN32
-struct accepting_socket {
- CRITICAL_SECTION lock;
- struct event_overlapped overlapped;
- SOCKET s;
- int error;
- struct event_callback deferred;
- struct evconnlistener_iocp *lev;
- ev_uint8_t buflen;
- ev_uint8_t family;
- unsigned free_on_cb:1;
- char addrbuf[1];
-};
-
-static void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key,
- ev_ssize_t n, int ok);
-static void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg);
-
-static void
-iocp_listener_event_add(struct evconnlistener_iocp *lev)
-{
- if (lev->event_added)
- return;
-
- lev->event_added = 1;
- event_base_add_virtual_(lev->event_base);
-}
-
-static void
-iocp_listener_event_del(struct evconnlistener_iocp *lev)
-{
- if (!lev->event_added)
- return;
-
- lev->event_added = 0;
- event_base_del_virtual_(lev->event_base);
-}
-
-static struct accepting_socket *
-new_accepting_socket(struct evconnlistener_iocp *lev, int family)
-{
- struct accepting_socket *res;
- int addrlen;
- int buflen;
-
- if (family == AF_INET)
- addrlen = sizeof(struct sockaddr_in);
- else if (family == AF_INET6)
- addrlen = sizeof(struct sockaddr_in6);
- else
- return NULL;
- buflen = (addrlen+16)*2;
-
- res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen);
- if (!res)
- return NULL;
-
- event_overlapped_init_(&res->overlapped, accepted_socket_cb);
- res->s = INVALID_SOCKET;
- res->lev = lev;
- res->buflen = buflen;
- res->family = family;
-
- event_deferred_cb_init_(&res->deferred,
- event_base_get_npriorities(lev->event_base) / 2,
- accepted_socket_invoke_user_cb, res);
-
- InitializeCriticalSectionAndSpinCount(&res->lock, 1000);
-
- return res;
-}
-
-static void
-free_and_unlock_accepting_socket(struct accepting_socket *as)
-{
- /* requires lock. */
- if (as->s != INVALID_SOCKET)
- closesocket(as->s);
-
- LeaveCriticalSection(&as->lock);
- DeleteCriticalSection(&as->lock);
- mm_free(as);
-}
-
-static int
-start_accepting(struct accepting_socket *as)
-{
- /* requires lock */
- const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
- DWORD pending = 0;
- SOCKET s = socket(as->family, SOCK_STREAM, 0);
- int error = 0;
-
- if (!as->lev->base.enabled)
- return 0;
-
- if (s == INVALID_SOCKET) {
- error = WSAGetLastError();
- goto report_err;
- }
-
- /* XXXX It turns out we need to do this again later. Does this call
- * have any effect? */
- setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- (char *)&as->lev->fd, sizeof(&as->lev->fd));
-
- if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING))
- evutil_make_socket_nonblocking(s);
-
- if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) {
- closesocket(s);
- return -1;
- }
-
- as->s = s;
-
- if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0,
- as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped))
- {
- /* Immediate success! */
- accepted_socket_cb(&as->overlapped, 1, 0, 1);
- } else {
- error = WSAGetLastError();
- if (error != ERROR_IO_PENDING) {
- goto report_err;
- }
- }
-
- return 0;
-
-report_err:
- as->error = error;
- event_deferred_cb_schedule_(
- as->lev->event_base,
- &as->deferred);
- return 0;
-}
-
-static void
-stop_accepting(struct accepting_socket *as)
-{
- /* requires lock. */
- SOCKET s = as->s;
- as->s = INVALID_SOCKET;
- closesocket(s);
-}
-
-static void
-accepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg)
-{
- struct accepting_socket *as = arg;
-
- struct sockaddr *sa_local=NULL, *sa_remote=NULL;
- int socklen_local=0, socklen_remote=0;
- const struct win32_extension_fns *ext = event_get_win32_extension_fns_();
- struct evconnlistener *lev = &as->lev->base;
- evutil_socket_t sock=-1;
- void *data;
- evconnlistener_cb cb=NULL;
- evconnlistener_errorcb errorcb=NULL;
- int error;
-
- EVUTIL_ASSERT(ext->GetAcceptExSockaddrs);
-
- LOCK(lev);
- EnterCriticalSection(&as->lock);
- if (as->free_on_cb) {
- free_and_unlock_accepting_socket(as);
- listener_decref_and_unlock(lev);
- return;
- }
-
- ++lev->refcnt;
-
- error = as->error;
- if (error) {
- as->error = 0;
- errorcb = lev->errorcb;
- } else {
- ext->GetAcceptExSockaddrs(
- as->addrbuf, 0, as->buflen/2, as->buflen/2,
- &sa_local, &socklen_local, &sa_remote,
- &socklen_remote);
- sock = as->s;
- cb = lev->cb;
- as->s = INVALID_SOCKET;
-
- /* We need to call this so getsockname, getpeername, and
- * shutdown work correctly on the accepted socket. */
- /* XXXX handle error? */
- setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
- (char *)&as->lev->fd, sizeof(&as->lev->fd));
- }
- data = lev->user_data;
-
- LeaveCriticalSection(&as->lock);
- UNLOCK(lev);
-
- if (errorcb) {
- WSASetLastError(error);
- errorcb(lev, data);
- } else if (cb) {
- cb(lev, sock, sa_remote, socklen_remote, data);
- }
-
- LOCK(lev);
- if (listener_decref_and_unlock(lev))
- return;
-
- EnterCriticalSection(&as->lock);
- start_accepting(as);
- LeaveCriticalSection(&as->lock);
-}
-
-static void
-accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok)
-{
- struct accepting_socket *as =
- EVUTIL_UPCAST(o, struct accepting_socket, overlapped);
-
- LOCK(&as->lev->base);
- EnterCriticalSection(&as->lock);
- if (ok) {
- /* XXXX Don't do this if some EV_MT flag is set. */
- event_deferred_cb_schedule_(
- as->lev->event_base,
- &as->deferred);
- LeaveCriticalSection(&as->lock);
- } else if (as->free_on_cb) {
- struct evconnlistener *lev = &as->lev->base;
- free_and_unlock_accepting_socket(as);
- listener_decref_and_unlock(lev);
- return;
- } else if (as->s == INVALID_SOCKET) {
- /* This is okay; we were disabled by iocp_listener_disable. */
- LeaveCriticalSection(&as->lock);
- } else {
- /* Some error on accept that we couldn't actually handle. */
- BOOL ok;
- DWORD transfer = 0, flags=0;
- event_sock_warn(as->s, "Unexpected error on AcceptEx");
- ok = WSAGetOverlappedResult(as->s, &o->overlapped,
- &transfer, FALSE, &flags);
- if (ok) {
- /* well, that was confusing! */
- as->error = 1;
- } else {
- as->error = WSAGetLastError();
- }
- event_deferred_cb_schedule_(
- as->lev->event_base,
- &as->deferred);
- LeaveCriticalSection(&as->lock);
- }
- UNLOCK(&as->lev->base);
-}
-
-static int
-iocp_listener_enable(struct evconnlistener *lev)
-{
- int i;
- struct evconnlistener_iocp *lev_iocp =
- EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
-
- LOCK(lev);
- iocp_listener_event_add(lev_iocp);
- for (i = 0; i < lev_iocp->n_accepting; ++i) {
- struct accepting_socket *as = lev_iocp->accepting[i];
- if (!as)
- continue;
- EnterCriticalSection(&as->lock);
- if (!as->free_on_cb && as->s == INVALID_SOCKET)
- start_accepting(as);
- LeaveCriticalSection(&as->lock);
- }
- UNLOCK(lev);
- return 0;
-}
-
-static int
-iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
-{
- int i;
- struct evconnlistener_iocp *lev_iocp =
- EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
-
- LOCK(lev);
- iocp_listener_event_del(lev_iocp);
- for (i = 0; i < lev_iocp->n_accepting; ++i) {
- struct accepting_socket *as = lev_iocp->accepting[i];
- if (!as)
- continue;
- EnterCriticalSection(&as->lock);
- if (!as->free_on_cb && as->s != INVALID_SOCKET) {
- if (shutdown)
- as->free_on_cb = 1;
- stop_accepting(as);
- }
- LeaveCriticalSection(&as->lock);
- }
-
- if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE)
- evutil_closesocket(lev_iocp->fd);
-
- UNLOCK(lev);
- return 0;
-}
-
-static int
-iocp_listener_disable(struct evconnlistener *lev)
-{
- return iocp_listener_disable_impl(lev,0);
-}
-
-static void
-iocp_listener_destroy(struct evconnlistener *lev)
-{
- struct evconnlistener_iocp *lev_iocp =
- EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
-
- if (! lev_iocp->shutting_down) {
- lev_iocp->shutting_down = 1;
- iocp_listener_disable_impl(lev,1);
- }
-
-}
-
-static evutil_socket_t
-iocp_listener_getfd(struct evconnlistener *lev)
-{
- struct evconnlistener_iocp *lev_iocp =
- EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
- return lev_iocp->fd;
-}
-static struct event_base *
-iocp_listener_getbase(struct evconnlistener *lev)
-{
- struct evconnlistener_iocp *lev_iocp =
- EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
- return lev_iocp->event_base;
-}
-
-static const struct evconnlistener_ops evconnlistener_iocp_ops = {
- iocp_listener_enable,
- iocp_listener_disable,
- iocp_listener_destroy,
- iocp_listener_destroy, /* shutdown */
- iocp_listener_getfd,
- iocp_listener_getbase
-};
-
-/* XXX define some way to override this. */
-#define N_SOCKETS_PER_LISTENER 4
-
-struct evconnlistener *
-evconnlistener_new_async(struct event_base *base,
- evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
- evutil_socket_t fd)
-{
- struct sockaddr_storage ss;
- int socklen = sizeof(ss);
- struct evconnlistener_iocp *lev;
- int i;
-
- flags |= LEV_OPT_THREADSAFE;
-
- if (!base || !event_base_get_iocp_(base))
- goto err;
-
- /* XXXX duplicate code */
- if (backlog > 0) {
- if (listen(fd, backlog) < 0)
- goto err;
- } else if (backlog < 0) {
- if (listen(fd, 128) < 0)
- goto err;
- }
- if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) {
- event_sock_warn(fd, "getsockname");
- goto err;
- }
- lev = mm_calloc(1, sizeof(struct evconnlistener_iocp));
- if (!lev) {
- event_warn("calloc");
- goto err;
- }
- lev->base.ops = &evconnlistener_iocp_ops;
- lev->base.cb = cb;
- lev->base.user_data = ptr;
- lev->base.flags = flags;
- lev->base.refcnt = 1;
- lev->base.enabled = 1;
-
- lev->port = event_base_get_iocp_(base);
- lev->fd = fd;
- lev->event_base = base;
-
-
- if (event_iocp_port_associate_(lev->port, fd, 1) < 0)
- goto err_free_lev;
-
- EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
-
- lev->n_accepting = N_SOCKETS_PER_LISTENER;
- lev->accepting = mm_calloc(lev->n_accepting,
- sizeof(struct accepting_socket *));
- if (!lev->accepting) {
- event_warn("calloc");
- goto err_delete_lock;
- }
- for (i = 0; i < lev->n_accepting; ++i) {
- lev->accepting[i] = new_accepting_socket(lev, ss.ss_family);
- if (!lev->accepting[i]) {
- event_warnx("Couldn't create accepting socket");
- goto err_free_accepting;
- }
- if (cb && start_accepting(lev->accepting[i]) < 0) {
- event_warnx("Couldn't start accepting on socket");
- EnterCriticalSection(&lev->accepting[i]->lock);
- free_and_unlock_accepting_socket(lev->accepting[i]);
- goto err_free_accepting;
- }
- ++lev->base.refcnt;
- }
-
- iocp_listener_event_add(lev);
-
- return &lev->base;
-
-err_free_accepting:
- mm_free(lev->accepting);
- /* XXXX free the other elements. */
-err_delete_lock:
- EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE);
-err_free_lev:
- mm_free(lev);
-err:
- /* Don't close the fd, it is caller's responsibility. */
- return NULL;
-}
-
-#endif
diff --git a/libs/libevent/src/log-internal.h b/libs/libevent/src/log-internal.h
deleted file mode 100644
index 330478a9ed..0000000000
--- a/libs/libevent/src/log-internal.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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_INTERNAL_H_INCLUDED_
-#define LOG_INTERNAL_H_INCLUDED_
-
-#include "event2/util.h"
-
-#ifdef __GNUC__
-#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
-#define EV_NORETURN __attribute__((noreturn))
-#else
-#define EV_CHECK_FMT(a,b)
-#define EV_NORETURN
-#endif
-
-#define EVENT_ERR_ABORT_ ((int)0xdeaddead)
-
-#define USE_GLOBAL_FOR_DEBUG_LOGGING
-
-#if !defined(EVENT__DISABLE_DEBUG_MODE) || defined(USE_DEBUG)
-#define EVENT_DEBUG_LOGGING_ENABLED
-#endif
-
-#ifdef EVENT_DEBUG_LOGGING_ENABLED
-#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
-extern ev_uint32_t event_debug_logging_mask_;
-#define event_debug_get_logging_mask_() (event_debug_logging_mask_)
-#else
-ev_uint32_t event_debug_get_logging_mask_(void);
-#endif
-#else
-#define event_debug_get_logging_mask_() (0)
-#endif
-
-void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
-void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
-void event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(3,4) EV_NORETURN;
-void event_sock_warn(evutil_socket_t sock, const char *fmt, ...) EV_CHECK_FMT(2,3);
-void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3) EV_NORETURN;
-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);
-
-void event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
- EV_CHECK_FMT(3,0);
-
-#ifdef EVENT_DEBUG_LOGGING_ENABLED
-#define event_debug(x) do { \
- if (event_debug_get_logging_mask_()) { \
- event_debugx_ x; \
- } \
- } while (0)
-#else
-#define event_debug(x) ((void)0)
-#endif
-
-#undef EV_CHECK_FMT
-
-#endif
diff --git a/libs/libevent/src/log.c b/libs/libevent/src/log.c
deleted file mode 100644
index e8ae9fdc31..0000000000
--- a/libs/libevent/src/log.c
+++ /dev/null
@@ -1,253 +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-2012 Niels Provos and Nick Mathewson
- *
- * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
- *
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#endif
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include "event2/event.h"
-#include "event2/util.h"
-
-#include "log-internal.h"
-
-static void event_log(int severity, const char *msg);
-static void event_exit(int errcode) EV_NORETURN;
-
-static event_fatal_cb fatal_fn = NULL;
-
-#ifdef EVENT_DEBUG_LOGGING_ENABLED
-#ifdef USE_DEBUG
-#define DEFAULT_MASK EVENT_DBG_ALL
-#else
-#define DEFAULT_MASK 0
-#endif
-
-#ifdef USE_GLOBAL_FOR_DEBUG_LOGGING
-ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
-#else
-static ev_uint32_t event_debug_logging_mask_ = DEFAULT_MASK;
-ev_uint32_t
-event_debug_get_logging_mask_(void)
-{
- return event_debug_logging_mask_;
-}
-#endif
-#endif /* EVENT_DEBUG_LOGGING_ENABLED */
-
-void
-event_enable_debug_logging(ev_uint32_t which)
-{
-#ifdef EVENT_DEBUG_LOGGING_ENABLED
- event_debug_logging_mask_ = which;
-#endif
-}
-
-void
-event_set_fatal_callback(event_fatal_cb cb)
-{
- fatal_fn = cb;
-}
-
-static void
-event_exit(int errcode)
-{
- if (fatal_fn) {
- fatal_fn(errcode);
- exit(errcode); /* should never be reached */
- } else if (errcode == EVENT_ERR_ABORT_)
- abort();
- else
- exit(errcode);
-}
-
-void
-event_err(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_ERR, strerror(errno), fmt, ap);
- va_end(ap);
- event_exit(eval);
-}
-
-void
-event_warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_WARN, strerror(errno), fmt, ap);
- va_end(ap);
-}
-
-void
-event_sock_err(int eval, evutil_socket_t sock, const char *fmt, ...)
-{
- va_list ap;
- int err = evutil_socket_geterror(sock);
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_ERR, evutil_socket_error_to_string(err), fmt, ap);
- va_end(ap);
- event_exit(eval);
-}
-
-void
-event_sock_warn(evutil_socket_t sock, const char *fmt, ...)
-{
- va_list ap;
- int err = evutil_socket_geterror(sock);
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_WARN, evutil_socket_error_to_string(err), fmt, ap);
- va_end(ap);
-}
-
-void
-event_errx(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_ERR, NULL, fmt, ap);
- va_end(ap);
- event_exit(eval);
-}
-
-void
-event_warnx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_WARN, NULL, fmt, ap);
- va_end(ap);
-}
-
-void
-event_msgx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_MSG, NULL, fmt, ap);
- va_end(ap);
-}
-
-void
-event_debugx_(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- event_logv_(EVENT_LOG_DEBUG, NULL, fmt, ap);
- va_end(ap);
-}
-
-void
-event_logv_(int severity, const char *errstr, const char *fmt, va_list ap)
-{
- char buf[1024];
- size_t len;
-
- if (severity == EVENT_LOG_DEBUG && !event_debug_get_logging_mask_())
- return;
-
- if (fmt != NULL)
- evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
- else
- buf[0] = '\0';
-
- if (errstr) {
- len = strlen(buf);
- if (len < sizeof(buf) - 3) {
- evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);
- }
- }
-
- 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/libs/libevent/src/minheap-internal.h b/libs/libevent/src/minheap-internal.h
deleted file mode 100644
index b3b6f1fd49..0000000000
--- a/libs/libevent/src/minheap-internal.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@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 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 MINHEAP_INTERNAL_H_INCLUDED_
-#define MINHEAP_INTERNAL_H_INCLUDED_
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "event2/util.h"
-#include "util-internal.h"
-#include "mm-internal.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_elt_is_top_(const struct event *e);
-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_adjust_(min_heap_t *s, struct event* e);
-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_up_unconditional_(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);
-
-#define min_heap_elem_greater(a, b) \
- (evutil_timercmp(&(a)->ev_timeout, &(b)->ev_timeout, >))
-
-void min_heap_ctor_(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
-void min_heap_dtor_(min_heap_t* s) { if (s->p) mm_free(s->p); }
-void min_heap_elem_init_(struct event* e) { e->ev_timeout_pos.min_heap_idx = -1; }
-int min_heap_empty_(min_heap_t* s) { return 0u == s->n; }
-unsigned min_heap_size_(min_heap_t* s) { return s->n; }
-struct event* min_heap_top_(min_heap_t* s) { return s->n ? *s->p : 0; }
-
-int min_heap_push_(min_heap_t* s, struct event* e)
-{
- if (min_heap_reserve_(s, s->n + 1))
- return -1;
- min_heap_shift_up_(s, s->n++, e);
- return 0;
-}
-
-struct event* min_heap_pop_(min_heap_t* s)
-{
- if (s->n)
- {
- struct event* e = *s->p;
- min_heap_shift_down_(s, 0u, s->p[--s->n]);
- e->ev_timeout_pos.min_heap_idx = -1;
- return e;
- }
- return 0;
-}
-
-int min_heap_elt_is_top_(const struct event *e)
-{
- return e->ev_timeout_pos.min_heap_idx == 0;
-}
-
-int min_heap_erase_(min_heap_t* s, struct event* e)
-{
- if (-1 != e->ev_timeout_pos.min_heap_idx)
- {
- struct event *last = s->p[--s->n];
- unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
- /* we replace e with the last element in the heap. We might need to
- shift it upward if it is less than its parent, or downward if it is
- greater than one or both its children. Since the children are known
- to be less than the parent, it can't need to shift both up and
- down. */
- if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
- min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, last);
- else
- min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, last);
- e->ev_timeout_pos.min_heap_idx = -1;
- return 0;
- }
- return -1;
-}
-
-int min_heap_adjust_(min_heap_t *s, struct event *e)
-{
- if (-1 == e->ev_timeout_pos.min_heap_idx) {
- return min_heap_push_(s, e);
- } else {
- unsigned parent = (e->ev_timeout_pos.min_heap_idx - 1) / 2;
- /* The position of e has changed; we shift it up or down
- * as needed. We can't need to do both. */
- if (e->ev_timeout_pos.min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], e))
- min_heap_shift_up_unconditional_(s, e->ev_timeout_pos.min_heap_idx, e);
- else
- min_heap_shift_down_(s, e->ev_timeout_pos.min_heap_idx, e);
- return 0;
- }
-}
-
-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**)mm_realloc(s->p, a * sizeof *p)))
- return -1;
- s->p = p;
- s->a = a;
- }
- return 0;
-}
-
-void min_heap_shift_up_unconditional_(min_heap_t* s, unsigned hole_index, struct event* e)
-{
- unsigned parent = (hole_index - 1) / 2;
- do
- {
- (s->p[hole_index] = s->p[parent])->ev_timeout_pos.min_heap_idx = hole_index;
- hole_index = parent;
- parent = (hole_index - 1) / 2;
- } while (hole_index && min_heap_elem_greater(s->p[parent], e));
- (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
-}
-
-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])->ev_timeout_pos.min_heap_idx = hole_index;
- hole_index = parent;
- parent = (hole_index - 1) / 2;
- }
- (s->p[hole_index] = e)->ev_timeout_pos.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])->ev_timeout_pos.min_heap_idx = hole_index;
- hole_index = min_child;
- min_child = 2 * (hole_index + 1);
- }
- (s->p[hole_index] = e)->ev_timeout_pos.min_heap_idx = hole_index;
-}
-
-#endif /* MINHEAP_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/mm-internal.h b/libs/libevent/src/mm-internal.h
deleted file mode 100644
index 4ba6fce4ad..0000000000
--- a/libs/libevent/src/mm-internal.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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 MM_INTERNAL_H_INCLUDED_
-#define MM_INTERNAL_H_INCLUDED_
-
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef EVENT__DISABLE_MM_REPLACEMENT
-/* Internal use only: Memory allocation functions. We give them nice short
- * mm_names for our own use, but make sure that the symbols have longer names
- * so they don't conflict with other libraries (like, say, libmm). */
-
-/** Allocate uninitialized memory.
- *
- * @return On success, return a pointer to sz newly allocated bytes.
- * On failure, set errno to ENOMEM and return NULL.
- * If the argument sz is 0, simply return NULL.
- */
-void *event_mm_malloc_(size_t sz);
-
-/** Allocate memory initialized to zero.
- *
- * @return On success, return a pointer to (count * size) newly allocated
- * bytes, initialized to zero.
- * On failure, or if the product would result in an integer overflow,
- * set errno to ENOMEM and return NULL.
- * If either arguments are 0, simply return NULL.
- */
-void *event_mm_calloc_(size_t count, size_t size);
-
-/** Duplicate a string.
- *
- * @return On success, return a pointer to a newly allocated duplicate
- * of a string.
- * Set errno to ENOMEM and return NULL if a memory allocation error
- * occurs (or would occur) in the process.
- * If the argument str is NULL, set errno to EINVAL and return NULL.
- */
-char *event_mm_strdup_(const char *str);
-
-void *event_mm_realloc_(void *p, size_t sz);
-void event_mm_free_(void *p);
-#define mm_malloc(sz) event_mm_malloc_(sz)
-#define mm_calloc(count, size) event_mm_calloc_((count), (size))
-#define mm_strdup(s) event_mm_strdup_(s)
-#define mm_realloc(p, sz) event_mm_realloc_((p), (sz))
-#define mm_free(p) event_mm_free_(p)
-#else
-#define mm_malloc(sz) malloc(sz)
-#define mm_calloc(n, sz) calloc((n), (sz))
-#define mm_strdup(s) strdup(s)
-#define mm_realloc(p, sz) realloc((p), (sz))
-#define mm_free(p) free(p)
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/libevent/src/ratelim-internal.h b/libs/libevent/src/ratelim-internal.h
deleted file mode 100644
index 6cc1cdde2c..0000000000
--- a/libs/libevent/src/ratelim-internal.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
- *
- * 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 RATELIM_INTERNAL_H_INCLUDED_
-#define RATELIM_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/util.h"
-
-/** A token bucket is an internal structure that tracks how many bytes we are
- * currently willing to read or write on a given bufferevent or group of
- * bufferevents */
-struct ev_token_bucket {
- /** How many bytes are we willing to read or write right now? These
- * values are signed so that we can do "defecit spending" */
- ev_ssize_t read_limit, write_limit;
- /** When was this bucket last updated? Measured in abstract 'ticks'
- * relative to the token bucket configuration. */
- ev_uint32_t last_updated;
-};
-
-/** Configuration info for a token bucket or set of token buckets. */
-struct ev_token_bucket_cfg {
- /** How many bytes are we willing to read on average per tick? */
- size_t read_rate;
- /** How many bytes are we willing to read at most in any one tick? */
- size_t read_maximum;
- /** How many bytes are we willing to write on average per tick? */
- size_t write_rate;
- /** How many bytes are we willing to write at most in any one tick? */
- size_t write_maximum;
-
- /* How long is a tick? Note that fractions of a millisecond are
- * ignored. */
- struct timeval tick_timeout;
-
- /* How long is a tick, in milliseconds? Derived from tick_timeout. */
- unsigned msec_per_tick;
-};
-
-/** The current tick is 'current_tick': add bytes to 'bucket' as specified in
- * 'cfg'. */
-int ev_token_bucket_update_(struct ev_token_bucket *bucket,
- const struct ev_token_bucket_cfg *cfg,
- ev_uint32_t current_tick);
-
-/** In which tick does 'tv' fall according to 'cfg'? Note that ticks can
- * overflow easily; your code needs to handle this. */
-ev_uint32_t ev_token_bucket_get_tick_(const struct timeval *tv,
- const struct ev_token_bucket_cfg *cfg);
-
-/** Adjust 'bucket' to respect 'cfg', and note that it was last updated in
- * 'current_tick'. If 'reinitialize' is true, we are changing the
- * configuration of 'bucket'; otherwise, we are setting it up for the first
- * time.
- */
-int ev_token_bucket_init_(struct ev_token_bucket *bucket,
- const struct ev_token_bucket_cfg *cfg,
- ev_uint32_t current_tick,
- int reinitialize);
-
-int bufferevent_remove_from_rate_limit_group_internal_(struct bufferevent *bev,
- int unsuspend);
-
-/** Decrease the read limit of 'b' by 'n' bytes */
-#define ev_token_bucket_decrement_read(b,n) \
- do { \
- (b)->read_limit -= (n); \
- } while (0)
-/** Decrease the write limit of 'b' by 'n' bytes */
-#define ev_token_bucket_decrement_write(b,n) \
- do { \
- (b)->write_limit -= (n); \
- } while (0)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/libevent/src/signal.c b/libs/libevent/src/signal.c
deleted file mode 100644
index 3f46295024..0000000000
--- a/libs/libevent/src/signal.c
+++ /dev/null
@@ -1,479 +0,0 @@
-/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
-
-/*
- * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright 2007-2012 Niels Provos and Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#endif
-#include <sys/types.h>
-#ifdef EVENT__HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <sys/queue.h>
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef EVENT__HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-#ifdef EVENT__HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#include "event2/event.h"
-#include "event2/event_struct.h"
-#include "event-internal.h"
-#include "event2/util.h"
-#include "evsignal-internal.h"
-#include "log-internal.h"
-#include "evmap-internal.h"
-#include "evthread-internal.h"
-
-/*
- signal.c
-
- This is the signal-handling implementation we use for backends that don't
- have a better way to do signal handling. It uses sigaction() or signal()
- to set a signal handler, and a socket pair to tell the event base when
-
- Note that I said "the event base" : only one event base can be set up to use
- this at a time. For historical reasons and backward compatibility, if you
- add an event for a signal to event_base A, then add an event for a signal
- (any signal!) to event_base B, event_base B will get informed about the
- signal, but event_base A won't.
-
- It would be neat to change this behavior in some future version of Libevent.
- kqueue already does something far more sensible. We can make all backends
- on Linux do a reasonable thing using signalfd.
-*/
-
-#ifndef _WIN32
-/* Windows wants us to call our signal handlers as __cdecl. Nobody else
- * expects you to do anything crazy like this. */
-#define __cdecl
-#endif
-
-static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
-static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
-
-static const struct eventop evsigops = {
- "signal",
- NULL,
- evsig_add,
- evsig_del,
- NULL,
- NULL,
- 0, 0, 0
-};
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-/* Lock for evsig_base and evsig_base_n_signals_added fields. */
-static void *evsig_base_lock = NULL;
-#endif
-/* The event base that's currently getting informed about signals. */
-static struct event_base *evsig_base = NULL;
-/* A copy of evsig_base->sigev_n_signals_added. */
-static int evsig_base_n_signals_added = 0;
-static evutil_socket_t evsig_base_fd = -1;
-
-static void __cdecl evsig_handler(int sig);
-
-#define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
-#define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
-
-void
-evsig_set_base_(struct event_base *base)
-{
- EVSIGBASE_LOCK();
- evsig_base = base;
- evsig_base_n_signals_added = base->sig.ev_n_signals_added;
- evsig_base_fd = base->sig.ev_signal_pair[1];
- EVSIGBASE_UNLOCK();
-}
-
-/* Callback for when the signal handler write a byte to our signaling socket */
-static void
-evsig_cb(evutil_socket_t fd, short what, void *arg)
-{
- static char signals[1024];
- ev_ssize_t n;
- int i;
- int ncaught[NSIG];
- struct event_base *base;
-
- base = arg;
-
- memset(&ncaught, 0, sizeof(ncaught));
-
- while (1) {
-#ifdef _WIN32
- n = recv(fd, signals, sizeof(signals), 0);
-#else
- n = read(fd, signals, sizeof(signals));
-#endif
- if (n == -1) {
- int err = evutil_socket_geterror(fd);
- if (! EVUTIL_ERR_RW_RETRIABLE(err))
- event_sock_err(1, fd, "%s: recv", __func__);
- break;
- } else if (n == 0) {
- /* XXX warn? */
- break;
- }
- for (i = 0; i < n; ++i) {
- ev_uint8_t sig = signals[i];
- if (sig < NSIG)
- ncaught[sig]++;
- }
- }
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
- for (i = 0; i < NSIG; ++i) {
- if (ncaught[i])
- evmap_signal_active_(base, i, ncaught[i]);
- }
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-}
-
-int
-evsig_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_make_internal_pipe_(base->sig.ev_signal_pair) == -1) {
-#ifdef _WIN32
- /* Make this nonfatal on win32, where sometimes people
- have localhost firewalled. */
- event_sock_warn(-1, "%s: socketpair", __func__);
-#else
- event_sock_err(1, -1, "%s: socketpair", __func__);
-#endif
- return -1;
- }
-
- if (base->sig.sh_old) {
- mm_free(base->sig.sh_old);
- }
- base->sig.sh_old = NULL;
- base->sig.sh_old_max = 0;
-
- event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0],
- EV_READ | EV_PERSIST, evsig_cb, base);
-
- base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
- event_priority_set(&base->sig.ev_signal, 0);
-
- base->evsigsel = &evsigops;
-
- return 0;
-}
-
-/* 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
-evsig_set_handler_(struct event_base *base,
- int evsignal, void (__cdecl *handler)(int))
-{
-#ifdef EVENT__HAVE_SIGACTION
- struct sigaction sa;
-#else
- ev_sighandler_t sh;
-#endif
- struct evsig_info *sig = &base->sig;
- void *p;
-
- /*
- * resize saved signal handler array up to the highest signal number.
- * a dynamic array is used to keep footprint on the low side.
- */
- if (evsignal >= sig->sh_old_max) {
- int new_max = evsignal + 1;
- event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
- __func__, evsignal, sig->sh_old_max));
- p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
- if (p == NULL) {
- event_warn("realloc");
- return (-1);
- }
-
- memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
- 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
-
- sig->sh_old_max = new_max;
- sig->sh_old = p;
- }
-
- /* allocate space for previous handler out of dynamic array */
- sig->sh_old[evsignal] = mm_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 EVENT__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");
- mm_free(sig->sh_old[evsignal]);
- sig->sh_old[evsignal] = NULL;
- return (-1);
- }
-#else
- if ((sh = signal(evsignal, handler)) == SIG_ERR) {
- event_warn("signal");
- mm_free(sig->sh_old[evsignal]);
- sig->sh_old[evsignal] = NULL;
- return (-1);
- }
- *sig->sh_old[evsignal] = sh;
-#endif
-
- return (0);
-}
-
-static int
-evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
-{
- struct evsig_info *sig = &base->sig;
- (void)p;
-
- EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
-
- /* catch signals if they happen quickly */
- EVSIGBASE_LOCK();
- if (evsig_base != base && evsig_base_n_signals_added) {
- event_warnx("Added a signal to event base %p with signals "
- "already added to event_base %p. Only one can have "
- "signals at a time with the %s backend. The base with "
- "the most recently added signal or the most recent "
- "event_base_loop() call gets preference; do "
- "not rely on this behavior in future Libevent versions.",
- base, evsig_base, base->evsel->name);
- }
- evsig_base = base;
- evsig_base_n_signals_added = ++sig->ev_n_signals_added;
- evsig_base_fd = base->sig.ev_signal_pair[1];
- EVSIGBASE_UNLOCK();
-
- event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
- if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) {
- goto err;
- }
-
-
- if (!sig->ev_signal_added) {
- if (event_add_nolock_(&sig->ev_signal, NULL, 0))
- goto err;
- sig->ev_signal_added = 1;
- }
-
- return (0);
-
-err:
- EVSIGBASE_LOCK();
- --evsig_base_n_signals_added;
- --sig->ev_n_signals_added;
- EVSIGBASE_UNLOCK();
- return (-1);
-}
-
-int
-evsig_restore_handler_(struct event_base *base, int evsignal)
-{
- int ret = 0;
- struct evsig_info *sig = &base->sig;
-#ifdef EVENT__HAVE_SIGACTION
- struct sigaction *sh;
-#else
- ev_sighandler_t *sh;
-#endif
-
- if (evsignal >= sig->sh_old_max) {
- /* Can't actually restore. */
- /* XXXX.*/
- return 0;
- }
-
- /* restore previous handler */
- sh = sig->sh_old[evsignal];
- sig->sh_old[evsignal] = NULL;
-#ifdef EVENT__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
-
- mm_free(sh);
-
- return ret;
-}
-
-static int
-evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
-{
- EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
-
- event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
- __func__, EV_SOCK_ARG(evsignal)));
-
- EVSIGBASE_LOCK();
- --evsig_base_n_signals_added;
- --base->sig.ev_n_signals_added;
- EVSIGBASE_UNLOCK();
-
- return (evsig_restore_handler_(base, (int)evsignal));
-}
-
-static void __cdecl
-evsig_handler(int sig)
-{
- int save_errno = errno;
-#ifdef _WIN32
- int socket_errno = EVUTIL_SOCKET_ERROR();
-#endif
- ev_uint8_t msg;
-
- if (evsig_base == NULL) {
- event_warnx(
- "%s: received signal %d, but have no base configured",
- __func__, sig);
- return;
- }
-
-#ifndef EVENT__HAVE_SIGACTION
- signal(sig, evsig_handler);
-#endif
-
- /* Wake up our notification mechanism */
- msg = sig;
-#ifdef _WIN32
- send(evsig_base_fd, (char*)&msg, 1, 0);
-#else
- {
- int r = write(evsig_base_fd, (char*)&msg, 1);
- (void)r; /* Suppress 'unused return value' and 'unused var' */
- }
-#endif
- errno = save_errno;
-#ifdef _WIN32
- EVUTIL_SET_SOCKET_ERROR(socket_errno);
-#endif
-}
-
-void
-evsig_dealloc_(struct event_base *base)
-{
- int i = 0;
- if (base->sig.ev_signal_added) {
- event_del(&base->sig.ev_signal);
- base->sig.ev_signal_added = 0;
- }
- /* debug event is created in evsig_init_/event_assign even when
- * ev_signal_added == 0, so unassign is required */
- event_debug_unassign(&base->sig.ev_signal);
-
- for (i = 0; i < NSIG; ++i) {
- if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
- evsig_restore_handler_(base, i);
- }
- EVSIGBASE_LOCK();
- if (base == evsig_base) {
- evsig_base = NULL;
- evsig_base_n_signals_added = 0;
- evsig_base_fd = -1;
- }
- EVSIGBASE_UNLOCK();
-
- if (base->sig.ev_signal_pair[0] != -1) {
- evutil_closesocket(base->sig.ev_signal_pair[0]);
- base->sig.ev_signal_pair[0] = -1;
- }
- if (base->sig.ev_signal_pair[1] != -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 evsig_del() */
- if (base->sig.sh_old) {
- mm_free(base->sig.sh_old);
- base->sig.sh_old = NULL;
- }
-}
-
-static void
-evsig_free_globals_locks(void)
-{
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
- if (evsig_base_lock != NULL) {
- EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
- evsig_base_lock = NULL;
- }
-#endif
- return;
-}
-
-void
-evsig_free_globals_(void)
-{
- evsig_free_globals_locks();
-}
-
-#ifndef EVENT__DISABLE_THREAD_SUPPORT
-int
-evsig_global_setup_locks_(const int enable_locks)
-{
- EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
- return 0;
-}
-
-#endif
diff --git a/libs/libevent/src/stdafx.cxx b/libs/libevent/src/stdafx.cxx
deleted file mode 100644
index 0fb604da7c..0000000000
--- a/libs/libevent/src/stdafx.cxx
+++ /dev/null
@@ -1,2 +0,0 @@
-
-#include "stdafx.h" \ No newline at end of file
diff --git a/libs/libevent/src/stdafx.h b/libs/libevent/src/stdafx.h
deleted file mode 100644
index d78b7834c8..0000000000
--- a/libs/libevent/src/stdafx.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-// just a stub \ No newline at end of file
diff --git a/libs/libevent/src/strlcpy-internal.h b/libs/libevent/src/strlcpy-internal.h
deleted file mode 100644
index cfc27ec662..0000000000
--- a/libs/libevent/src/strlcpy-internal.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef STRLCPY_INTERNAL_H_INCLUDED_
-#define STRLCPY_INTERNAL_H_INCLUDED_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifndef EVENT__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/libs/libevent/src/strlcpy.c b/libs/libevent/src/strlcpy.c
deleted file mode 100644
index 3876475f5a..0000000000
--- a/libs/libevent/src/strlcpy.c
+++ /dev/null
@@ -1,75 +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 "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <sys/types.h>
-
-#ifndef EVENT__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
diff --git a/libs/libevent/src/time-internal.h b/libs/libevent/src/time-internal.h
deleted file mode 100644
index 2c584fa752..0000000000
--- a/libs/libevent/src/time-internal.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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 TIME_INTERNAL_H_INCLUDED_
-#define TIME_INTERNAL_H_INCLUDED_
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef EVENT__HAVE_MACH_MACH_TIME_H
-/* For mach_timebase_info */
-#include <mach/mach_time.h>
-#endif
-
-#include <time.h>
-
-#include "event2/util.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(EVENT__HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
-#define HAVE_POSIX_MONOTONIC
-#elif defined(EVENT__HAVE_MACH_ABSOLUTE_TIME)
-#define HAVE_MACH_MONOTONIC
-#elif defined(_WIN32)
-#define HAVE_WIN32_MONOTONIC
-#else
-#define HAVE_FALLBACK_MONOTONIC
-#endif
-
-long evutil_tv_to_msec_(const struct timeval *tv);
-void evutil_usleep_(const struct timeval *tv);
-
-#ifdef _WIN32
-typedef ULONGLONG (WINAPI *ev_GetTickCount_func)(void);
-#endif
-
-struct evutil_monotonic_timer {
-
-#ifdef HAVE_MACH_MONOTONIC
- struct mach_timebase_info mach_timebase_units;
-#endif
-
-#ifdef HAVE_POSIX_MONOTONIC
- int monotonic_clock;
-#endif
-
-#ifdef HAVE_WIN32_MONOTONIC
- ev_GetTickCount_func GetTickCount64_fn;
- ev_GetTickCount_func GetTickCount_fn;
- ev_uint64_t last_tick_count;
- ev_uint64_t adjust_tick_count;
-
- ev_uint64_t first_tick;
- ev_uint64_t first_counter;
- double usec_per_count;
- int use_performance_counter;
-#endif
-
- struct timeval adjust_monotonic_clock;
- struct timeval last_time;
-};
-
-int evutil_configure_monotonic_time_(struct evutil_monotonic_timer *mt,
- int flags);
-int evutil_gettime_monotonic_(struct evutil_monotonic_timer *mt, struct timeval *tv);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* EVENT_INTERNAL_H_INCLUDED_ */
diff --git a/libs/libevent/src/util-internal.h b/libs/libevent/src/util-internal.h
deleted file mode 100644
index 61db4e9aca..0000000000
--- a/libs/libevent/src/util-internal.h
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
- *
- * 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 UTIL_INTERNAL_H_INCLUDED_
-#define UTIL_INTERNAL_H_INCLUDED_
-
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#include <errno.h>
-
-/* For EVUTIL_ASSERT */
-#include "log-internal.h"
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef EVENT__HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef EVENT__HAVE_SYS_EVENTFD_H
-#include <sys/eventfd.h>
-#endif
-#include "event2/util.h"
-
-#include "time-internal.h"
-#include "ipv6-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* If we need magic to say "inline", get it for free internally. */
-#ifdef EVENT__inline
-#if(_MSC_VER < 1900)
-#define inline __inline
-#else
-#define inline EVENT__inline
-#endif
-
-
-#endif
-#ifdef EVENT____func__
-#define __func__ EVENT____func__
-#endif
-
-/* A good no-op to use in macro definitions. */
-#define EVUTIL_NIL_STMT_ ((void)0)
-/* A no-op that tricks the compiler into thinking a condition is used while
- * definitely not making any code for it. Used to compile out asserts while
- * avoiding "unused variable" warnings. The "!" forces the compiler to
- * do the sizeof() on an int, in case "condition" is a bitfield value.
- */
-#define EVUTIL_NIL_CONDITION_(condition) do { \
- (void)sizeof(!(condition)); \
-} while(0)
-
-/* Internal use only: macros to match patterns of error codes in a
- cross-platform way. We need these macros because of two historical
- reasons: first, nonblocking IO functions are generally written to give an
- error on the "blocked now, try later" case, so sometimes an error from a
- read, write, connect, or accept means "no error; just wait for more
- data," and we need to look at the error code. Second, Windows defines
- a different set of error codes for sockets. */
-
-#ifndef _WIN32
-
-#if EAGAIN == EWOULDBLOCK
-#define EVUTIL_ERR_IS_EAGAIN(e) \
- ((e) == EAGAIN)
-#else
-#define EVUTIL_ERR_IS_EAGAIN(e) \
- ((e) == EAGAIN || (e) == EWOULDBLOCK)
-#endif
-
-/* True iff e is an error that means a read/write operation can be retried. */
-#define EVUTIL_ERR_RW_RETRIABLE(e) \
- ((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e))
-/* True iff e is an error that means an connect can be retried. */
-#define EVUTIL_ERR_CONNECT_RETRIABLE(e) \
- ((e) == EINTR || (e) == EINPROGRESS)
-/* True iff e is an error that means a accept can be retried. */
-#define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \
- ((e) == EINTR || EVUTIL_ERR_IS_EAGAIN(e) || (e) == ECONNABORTED)
-
-/* True iff e is an error that means the connection was refused */
-#define EVUTIL_ERR_CONNECT_REFUSED(e) \
- ((e) == ECONNREFUSED)
-
-#else
-/* Win32 */
-
-#define EVUTIL_ERR_IS_EAGAIN(e) \
- ((e) == WSAEWOULDBLOCK || (e) == EAGAIN)
-
-#define EVUTIL_ERR_RW_RETRIABLE(e) \
- ((e) == WSAEWOULDBLOCK || \
- (e) == WSAEINTR)
-
-#define EVUTIL_ERR_CONNECT_RETRIABLE(e) \
- ((e) == WSAEWOULDBLOCK || \
- (e) == WSAEINTR || \
- (e) == WSAEINPROGRESS || \
- (e) == WSAEINVAL)
-
-#define EVUTIL_ERR_ACCEPT_RETRIABLE(e) \
- EVUTIL_ERR_RW_RETRIABLE(e)
-
-#define EVUTIL_ERR_CONNECT_REFUSED(e) \
- ((e) == WSAECONNREFUSED)
-
-#endif
-
-/* Arguments for shutdown() */
-#ifdef SHUT_RD
-#define EVUTIL_SHUT_RD SHUT_RD
-#else
-#define EVUTIL_SHUT_RD 0
-#endif
-#ifdef SHUT_WR
-#define EVUTIL_SHUT_WR SHUT_WR
-#else
-#define EVUTIL_SHUT_WR 1
-#endif
-#ifdef SHUT_BOTH
-#define EVUTIL_SHUT_BOTH SHUT_BOTH
-#else
-#define EVUTIL_SHUT_BOTH 2
-#endif
-
-/* Helper: Verify that all the elements in 'dlist' are internally consistent.
- * Checks for circular lists and bad prev/next pointers.
- *
- * Example usage:
- * EVUTIL_ASSERT_LIST_OK(eventlist, event, ev_next);
- */
-#define EVUTIL_ASSERT_LIST_OK(dlist, type, field) do { \
- struct type *elm1, *elm2, **nextp; \
- if (LIST_EMPTY((dlist))) \
- break; \
- \
- /* Check list for circularity using Floyd's */ \
- /* 'Tortoise and Hare' algorithm */ \
- elm1 = LIST_FIRST((dlist)); \
- elm2 = LIST_NEXT(elm1, field); \
- while (elm1 && elm2) { \
- EVUTIL_ASSERT(elm1 != elm2); \
- elm1 = LIST_NEXT(elm1, field); \
- elm2 = LIST_NEXT(elm2, field); \
- if (!elm2) \
- break; \
- EVUTIL_ASSERT(elm1 != elm2); \
- elm2 = LIST_NEXT(elm2, field); \
- } \
- \
- /* Now check next and prev pointers for consistency. */ \
- nextp = &LIST_FIRST((dlist)); \
- elm1 = LIST_FIRST((dlist)); \
- while (elm1) { \
- EVUTIL_ASSERT(*nextp == elm1); \
- EVUTIL_ASSERT(nextp == elm1->field.le_prev); \
- nextp = &LIST_NEXT(elm1, field); \
- elm1 = *nextp; \
- } \
- } while (0)
-
-/* Helper: Verify that all the elements in a TAILQ are internally consistent.
- * Checks for circular lists and bad prev/next pointers.
- *
- * Example usage:
- * EVUTIL_ASSERT_TAILQ_OK(activelist, event, ev_active_next);
- */
-#define EVUTIL_ASSERT_TAILQ_OK(tailq, type, field) do { \
- struct type *elm1, *elm2, **nextp; \
- if (TAILQ_EMPTY((tailq))) \
- break; \
- \
- /* Check list for circularity using Floyd's */ \
- /* 'Tortoise and Hare' algorithm */ \
- elm1 = TAILQ_FIRST((tailq)); \
- elm2 = TAILQ_NEXT(elm1, field); \
- while (elm1 && elm2) { \
- EVUTIL_ASSERT(elm1 != elm2); \
- elm1 = TAILQ_NEXT(elm1, field); \
- elm2 = TAILQ_NEXT(elm2, field); \
- if (!elm2) \
- break; \
- EVUTIL_ASSERT(elm1 != elm2); \
- elm2 = TAILQ_NEXT(elm2, field); \
- } \
- \
- /* Now check next and prev pointers for consistency. */ \
- nextp = &TAILQ_FIRST((tailq)); \
- elm1 = TAILQ_FIRST((tailq)); \
- while (elm1) { \
- EVUTIL_ASSERT(*nextp == elm1); \
- EVUTIL_ASSERT(nextp == elm1->field.tqe_prev); \
- nextp = &TAILQ_NEXT(elm1, field); \
- elm1 = *nextp; \
- } \
- EVUTIL_ASSERT(nextp == (tailq)->tqh_last); \
- } while (0)
-
-/* Locale-independent replacements for some ctypes functions. Use these
- * when you care about ASCII's notion of character types, because you are about
- * to send those types onto the wire.
- */
-int EVUTIL_ISALPHA_(char c);
-int EVUTIL_ISALNUM_(char c);
-int EVUTIL_ISSPACE_(char c);
-int EVUTIL_ISDIGIT_(char c);
-int EVUTIL_ISXDIGIT_(char c);
-int EVUTIL_ISPRINT_(char c);
-int EVUTIL_ISLOWER_(char c);
-int EVUTIL_ISUPPER_(char c);
-char EVUTIL_TOUPPER_(char c);
-char EVUTIL_TOLOWER_(char c);
-
-/** Remove all trailing horizontal whitespace (space or tab) from the end of a
- * string */
-void evutil_rtrim_lws_(char *);
-
-
-/** Helper macro. If we know that a given pointer points to a field in a
- structure, return a pointer to the structure itself. Used to implement
- our half-baked C OO. Example:
-
- struct subtype {
- int x;
- struct supertype common;
- int y;
- };
- ...
- void fn(struct supertype *super) {
- struct subtype *sub = EVUTIL_UPCAST(super, struct subtype, common);
- ...
- }
- */
-#define EVUTIL_UPCAST(ptr, type, field) \
- ((type *)(((char*)(ptr)) - evutil_offsetof(type, field)))
-
-/* As open(pathname, flags, mode), except that the file is always opened with
- * the close-on-exec flag set. (And the mode argument is mandatory.)
- */
-int evutil_open_closeonexec_(const char *pathname, int flags, unsigned mode);
-
-int evutil_read_file_(const char *filename, char **content_out, size_t *len_out,
- int is_binary);
-
-int evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen);
-
-int evutil_socket_finished_connecting_(evutil_socket_t fd);
-
-int evutil_ersatz_socketpair_(int, int , int, evutil_socket_t[]);
-
-int evutil_resolve_(int family, const char *hostname, struct sockaddr *sa,
- ev_socklen_t *socklen, int port);
-
-const char *evutil_getenv_(const char *name);
-
-/* Structure to hold the state of our weak random number generator.
- */
-struct evutil_weakrand_state {
- ev_uint32_t seed;
-};
-
-#define EVUTIL_WEAKRAND_MAX EV_INT32_MAX
-
-/* Initialize the state of a week random number generator based on 'seed'. If
- * the seed is 0, construct a new seed based on not-very-strong platform
- * entropy, like the PID and the time of day.
- *
- * This function, and the other evutil_weakrand* functions, are meant for
- * speed, not security or statistical strength. If you need a RNG which an
- * attacker can't predict, or which passes strong statistical tests, use the
- * evutil_secure_rng* functions instead.
- */
-ev_uint32_t evutil_weakrand_seed_(struct evutil_weakrand_state *state, ev_uint32_t seed);
-/* Return a pseudorandom value between 0 and EVUTIL_WEAKRAND_MAX inclusive.
- * Updates the state in 'seed' as needed -- this value must be protected by a
- * lock.
- */
-ev_int32_t evutil_weakrand_(struct evutil_weakrand_state *seed);
-/* Return a pseudorandom value x such that 0 <= x < top. top must be no more
- * than EVUTIL_WEAKRAND_MAX. Updates the state in 'seed' as needed -- this
- * value must be proteced by a lock */
-ev_int32_t evutil_weakrand_range_(struct evutil_weakrand_state *seed, ev_int32_t top);
-
-/* Evaluates to the same boolean value as 'p', and hints to the compiler that
- * we expect this value to be false. */
-#if defined(__GNUC__) && __GNUC__ >= 3 /* gcc 3.0 or later */
-#define EVUTIL_UNLIKELY(p) __builtin_expect(!!(p),0)
-#else
-#define EVUTIL_UNLIKELY(p) (p)
-#endif
-
-/* Replacement for assert() that calls event_errx on failure. */
-#ifdef NDEBUG
-#define EVUTIL_ASSERT(cond) EVUTIL_NIL_CONDITION_(cond)
-#define EVUTIL_FAILURE_CHECK(cond) 0
-#else
-#define EVUTIL_ASSERT(cond) \
- do { \
- if (EVUTIL_UNLIKELY(!(cond))) { \
- event_errx(EVENT_ERR_ABORT_, \
- "%s:%d: Assertion %s failed in %s", \
- __FILE__,__LINE__,#cond,__func__); \
- /* In case a user-supplied handler tries to */ \
- /* return control to us, log and abort here. */ \
- (void)fprintf(stderr, \
- "%s:%d: Assertion %s failed in %s", \
- __FILE__,__LINE__,#cond,__func__); \
- abort(); \
- } \
- } while (0)
-#define EVUTIL_FAILURE_CHECK(cond) EVUTIL_UNLIKELY(cond)
-#endif
-
-#ifndef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE
-/* Replacement for sockaddr storage that we can use internally on platforms
- * that lack it. It is not space-efficient, but neither is sockaddr_storage.
- */
-struct sockaddr_storage {
- union {
- struct sockaddr ss_sa;
- struct sockaddr_in ss_sin;
- struct sockaddr_in6 ss_sin6;
- char ss_padding[128];
- } ss_union;
-};
-#define ss_family ss_union.ss_sa.sa_family
-#endif
-
-/* Internal addrinfo error code. This one is returned from only from
- * evutil_getaddrinfo_common_, when we are sure that we'll have to hit a DNS
- * server. */
-#define EVUTIL_EAI_NEED_RESOLVE -90002
-
-struct evdns_base;
-struct evdns_getaddrinfo_request;
-typedef struct evdns_getaddrinfo_request* (*evdns_getaddrinfo_fn)(
- struct evdns_base *base,
- const char *nodename, const char *servname,
- const struct evutil_addrinfo *hints_in,
- void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
-
-void evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo_fn fn);
-
-struct evutil_addrinfo *evutil_new_addrinfo_(struct sockaddr *sa,
- ev_socklen_t socklen, const struct evutil_addrinfo *hints);
-struct evutil_addrinfo *evutil_addrinfo_append_(struct evutil_addrinfo *first,
- struct evutil_addrinfo *append);
-void evutil_adjust_hints_for_addrconfig_(struct evutil_addrinfo *hints);
-int evutil_getaddrinfo_common_(const char *nodename, const char *servname,
- struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum);
-
-int evutil_getaddrinfo_async_(struct evdns_base *dns_base,
- const char *nodename, const char *servname,
- const struct evutil_addrinfo *hints_in,
- void (*cb)(int, struct evutil_addrinfo *, void *), void *arg);
-
-/** Return true iff sa is a looback address. (That is, it is 127.0.0.1/8, or
- * ::1). */
-int evutil_sockaddr_is_loopback_(const struct sockaddr *sa);
-
-
-/**
- Formats a sockaddr sa into a string buffer of size outlen stored in out.
- Returns a pointer to out. Always writes something into out, so it's safe
- to use the output of this function without checking it for NULL.
- */
-const char *evutil_format_sockaddr_port_(const struct sockaddr *sa, char *out, size_t outlen);
-
-int evutil_hex_char_to_int_(char c);
-
-
-void evutil_free_secure_rng_globals_(void);
-void evutil_free_globals_(void);
-
-#ifdef _WIN32
-HMODULE evutil_load_windows_system_library_(const wchar_t *library_name);
-#endif
-
-#ifndef EV_SIZE_FMT
-#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
-#define EV_U64_FMT "%I64u"
-#define EV_I64_FMT "%I64d"
-#define EV_I64_ARG(x) ((__int64)(x))
-#define EV_U64_ARG(x) ((unsigned __int64)(x))
-#else
-#define EV_U64_FMT "%llu"
-#define EV_I64_FMT "%lld"
-#define EV_I64_ARG(x) ((long long)(x))
-#define EV_U64_ARG(x) ((unsigned long long)(x))
-#endif
-#endif
-
-#ifdef _WIN32
-#define EV_SOCK_FMT EV_I64_FMT
-#define EV_SOCK_ARG(x) EV_I64_ARG((x))
-#else
-#define EV_SOCK_FMT "%d"
-#define EV_SOCK_ARG(x) (x)
-#endif
-
-#if defined(__STDC__) && defined(__STDC_VERSION__) && !defined(__MINGW64_VERSION_MAJOR)
-#if (__STDC_VERSION__ >= 199901L)
-#define EV_SIZE_FMT "%zu"
-#define EV_SSIZE_FMT "%zd"
-#define EV_SIZE_ARG(x) (x)
-#define EV_SSIZE_ARG(x) (x)
-#endif
-#endif
-
-#ifndef EV_SIZE_FMT
-#if (EVENT__SIZEOF_SIZE_T <= EVENT__SIZEOF_LONG)
-#define EV_SIZE_FMT "%lu"
-#define EV_SSIZE_FMT "%ld"
-#define EV_SIZE_ARG(x) ((unsigned long)(x))
-#define EV_SSIZE_ARG(x) ((long)(x))
-#else
-#define EV_SIZE_FMT EV_U64_FMT
-#define EV_SSIZE_FMT EV_I64_FMT
-#define EV_SIZE_ARG(x) EV_U64_ARG(x)
-#define EV_SSIZE_ARG(x) EV_I64_ARG(x)
-#endif
-#endif
-
-evutil_socket_t evutil_socket_(int domain, int type, int protocol);
-evutil_socket_t evutil_accept4_(evutil_socket_t sockfd, struct sockaddr *addr,
- ev_socklen_t *addrlen, int flags);
-
- /* used by one of the test programs.. */
-EVENT2_EXPORT_SYMBOL
-int evutil_make_internal_pipe_(evutil_socket_t fd[2]);
-evutil_socket_t evutil_eventfd_(unsigned initval, int flags);
-
-#ifdef SOCK_NONBLOCK
-#define EVUTIL_SOCK_NONBLOCK SOCK_NONBLOCK
-#else
-#define EVUTIL_SOCK_NONBLOCK 0x4000000
-#endif
-#ifdef SOCK_CLOEXEC
-#define EVUTIL_SOCK_CLOEXEC SOCK_CLOEXEC
-#else
-#define EVUTIL_SOCK_CLOEXEC 0x80000000
-#endif
-#ifdef EFD_NONBLOCK
-#define EVUTIL_EFD_NONBLOCK EFD_NONBLOCK
-#else
-#define EVUTIL_EFD_NONBLOCK 0x4000
-#endif
-#ifdef EFD_CLOEXEC
-#define EVUTIL_EFD_CLOEXEC EFD_CLOEXEC
-#else
-#define EVUTIL_EFD_CLOEXEC 0x8000
-#endif
-
-void evutil_memclear_(void *mem, size_t len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/libevent/src/win32select.c b/libs/libevent/src/win32select.c
deleted file mode 100644
index 1766858c2c..0000000000
--- a/libs/libevent/src/win32select.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright 2007-2012 Niels Provos and Nick Mathewson
- * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
- * Copyright 2003 Michael A. Davis <mike@datanerds.net>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "event2/event-config.h"
-#include "evconfig-private.h"
-
-#ifdef _WIN32
-
-#include <winsock2.h>
-#include <windows.h>
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "event2/util.h"
-#include "util-internal.h"
-#include "log-internal.h"
-#include "event2/event.h"
-#include "event-internal.h"
-#include "evmap-internal.h"
-#include "event2/thread.h"
-#include "evthread-internal.h"
-#include "time-internal.h"
-
-#define XFREE(ptr) do { if (ptr) mm_free(ptr); } while (0)
-
-extern struct event_list timequeue;
-extern struct event_list addqueue;
-
-struct win_fd_set {
- unsigned int fd_count;
- SOCKET fd_array[1];
-};
-
-/* MSDN says this is required to handle SIGFPE */
-volatile double SIGFPE_REQ = 0.0f;
-
-struct idx_info {
- int read_pos_plus1;
- int write_pos_plus1;
-};
-
-struct win32op {
- unsigned num_fds_in_fd_sets;
- int resize_out_sets;
- 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;
- unsigned signals_are_broken : 1;
-};
-
-static void *win32_init(struct event_base *);
-static int win32_add(struct event_base *, evutil_socket_t, short old, short events, void *idx_);
-static int win32_del(struct event_base *, evutil_socket_t, short old, short events, void *idx_);
-static int win32_dispatch(struct event_base *base, struct timeval *);
-static void win32_dealloc(struct event_base *);
-
-struct eventop win32ops = {
- "win32",
- win32_init,
- win32_add,
- win32_del,
- win32_dispatch,
- win32_dealloc,
- 0, /* doesn't need reinit */
- 0, /* No features supported. */
- sizeof(struct idx_info),
-};
-
-#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
-
-static int
-grow_fd_sets(struct win32op *op, unsigned new_num_fds)
-{
- size_t size;
-
- EVUTIL_ASSERT(new_num_fds >= op->readset_in->fd_count &&
- new_num_fds >= op->writeset_in->fd_count);
- EVUTIL_ASSERT(new_num_fds >= 1);
-
- size = FD_SET_ALLOC_SIZE(new_num_fds);
- if (!(op->readset_in = mm_realloc(op->readset_in, size)))
- return (-1);
- if (!(op->writeset_in = mm_realloc(op->writeset_in, size)))
- return (-1);
- op->resize_out_sets = 1;
- op->num_fds_in_fd_sets = new_num_fds;
- return (0);
-}
-
-static int
-do_fd_set(struct win32op *op, struct idx_info *ent, evutil_socket_t s, int read)
-{
- struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
- if (read) {
- if (ent->read_pos_plus1 > 0)
- return (0);
- } else {
- if (ent->write_pos_plus1 > 0)
- return (0);
- }
- if (set->fd_count == op->num_fds_in_fd_sets) {
- if (grow_fd_sets(op, op->num_fds_in_fd_sets*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_plus1 = set->fd_count+1;
- else
- ent->write_pos_plus1 = set->fd_count+1;
- return (set->fd_count++);
-}
-
-static int
-do_fd_clear(struct event_base *base,
- struct win32op *op, struct idx_info *ent, int read)
-{
- int i;
- struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
- if (read) {
- i = ent->read_pos_plus1 - 1;
- ent->read_pos_plus1 = 0;
- } else {
- i = ent->write_pos_plus1 - 1;
- ent->write_pos_plus1 = 0;
- }
- if (i < 0)
- return (0);
- if (--set->fd_count != (unsigned)i) {
- struct idx_info *ent2;
- SOCKET s2;
- s2 = set->fd_array[i] = set->fd_array[set->fd_count];
-
- ent2 = evmap_io_get_fdinfo_(&base->io, s2);
-
- if (!ent2) /* This indicates a bug. */
- return (0);
- if (read)
- ent2->read_pos_plus1 = i+1;
- else
- ent2->write_pos_plus1 = i+1;
- }
- return (0);
-}
-
-#define NEVENT 32
-void *
-win32_init(struct event_base *base)
-{
- struct win32op *winop;
- size_t size;
- if (!(winop = mm_calloc(1, sizeof(struct win32op))))
- return NULL;
- winop->num_fds_in_fd_sets = NEVENT;
- size = FD_SET_ALLOC_SIZE(NEVENT);
- if (!(winop->readset_in = mm_malloc(size)))
- goto err;
- if (!(winop->writeset_in = mm_malloc(size)))
- goto err;
- if (!(winop->readset_out = mm_malloc(size)))
- goto err;
- if (!(winop->writeset_out = mm_malloc(size)))
- goto err;
- if (!(winop->exset_out = mm_malloc(size)))
- goto err;
- 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;
-
- if (evsig_init_(base) < 0)
- winop->signals_are_broken = 1;
-
- evutil_weakrand_seed_(&base->weakrand_seed, 0);
-
- 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_add(struct event_base *base, evutil_socket_t fd,
- short old, short events, void *idx_)
-{
- struct win32op *win32op = base->evbase;
- struct idx_info *idx = idx_;
-
- if ((events & EV_SIGNAL) && win32op->signals_are_broken)
- return (-1);
-
- if (!(events & (EV_READ|EV_WRITE)))
- return (0);
-
- event_debug(("%s: adding event for %d", __func__, (int)fd));
- if (events & EV_READ) {
- if (do_fd_set(win32op, idx, fd, 1)<0)
- return (-1);
- }
- if (events & EV_WRITE) {
- if (do_fd_set(win32op, idx, fd, 0)<0)
- return (-1);
- }
- return (0);
-}
-
-int
-win32_del(struct event_base *base, evutil_socket_t fd, short old, short events,
- void *idx_)
-{
- struct win32op *win32op = base->evbase;
- struct idx_info *idx = idx_;
-
- event_debug(("%s: Removing event for "EV_SOCK_FMT,
- __func__, EV_SOCK_ARG(fd)));
- if (events & EV_READ)
- do_fd_clear(base, win32op, idx, 1);
- if (events & EV_WRITE)
- do_fd_clear(base, win32op, idx, 0);
-
- 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, struct timeval *tv)
-{
- struct win32op *win32op = base->evbase;
- int res = 0;
- unsigned j, i;
- int fd_count;
- SOCKET s;
-
- if (win32op->resize_out_sets) {
- size_t size = FD_SET_ALLOC_SIZE(win32op->num_fds_in_fd_sets);
- if (!(win32op->readset_out = mm_realloc(win32op->readset_out, size)))
- return (-1);
- if (!(win32op->exset_out = mm_realloc(win32op->exset_out, size)))
- return (-1);
- if (!(win32op->writeset_out = mm_realloc(win32op->writeset_out, size)))
- return (-1);
- win32op->resize_out_sets = 0;
- }
-
- fd_set_copy(win32op->readset_out, win32op->readset_in);
- fd_set_copy(win32op->exset_out, win32op->writeset_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) {
- long msec = tv ? evutil_tv_to_msec_(tv) : LONG_MAX;
- /* Sleep's DWORD argument is unsigned long */
- if (msec < 0)
- msec = LONG_MAX;
- /* Windows doesn't like you to call select() with no sockets */
- Sleep(msec);
- return (0);
- }
-
- EVBASE_RELEASE_LOCK(base, th_base_lock);
-
- res = select(fd_count,
- (struct fd_set*)win32op->readset_out,
- (struct fd_set*)win32op->writeset_out,
- (struct fd_set*)win32op->exset_out, tv);
-
- EVBASE_ACQUIRE_LOCK(base, th_base_lock);
-
- event_debug(("%s: select returned %d", __func__, res));
-
- if (res <= 0) {
- return res;
- }
-
- if (win32op->readset_out->fd_count) {
- i = evutil_weakrand_range_(&base->weakrand_seed,
- win32op->readset_out->fd_count);
- for (j=0; j<win32op->readset_out->fd_count; ++j) {
- if (++i >= win32op->readset_out->fd_count)
- i = 0;
- s = win32op->readset_out->fd_array[i];
- evmap_io_active_(base, s, EV_READ);
- }
- }
- if (win32op->exset_out->fd_count) {
- i = evutil_weakrand_range_(&base->weakrand_seed,
- win32op->exset_out->fd_count);
- for (j=0; j<win32op->exset_out->fd_count; ++j) {
- if (++i >= win32op->exset_out->fd_count)
- i = 0;
- s = win32op->exset_out->fd_array[i];
- evmap_io_active_(base, s, EV_WRITE);
- }
- }
- if (win32op->writeset_out->fd_count) {
- SOCKET s;
- i = evutil_weakrand_range_(&base->weakrand_seed,
- win32op->writeset_out->fd_count);
- for (j=0; j<win32op->writeset_out->fd_count; ++j) {
- if (++i >= win32op->writeset_out->fd_count)
- i = 0;
- s = win32op->writeset_out->fd_array[i];
- evmap_io_active_(base, s, EV_WRITE);
- }
- }
- return (0);
-}
-
-void
-win32_dealloc(struct event_base *base)
-{
- struct win32op *win32op = base->evbase;
-
- evsig_dealloc_(base);
- if (win32op->readset_in)
- mm_free(win32op->readset_in);
- if (win32op->writeset_in)
- mm_free(win32op->writeset_in);
- if (win32op->readset_out)
- mm_free(win32op->readset_out);
- if (win32op->writeset_out)
- mm_free(win32op->writeset_out);
- if (win32op->exset_out)
- mm_free(win32op->exset_out);
- /* XXXXX free the tree. */
-
- memset(win32op, 0, sizeof(*win32op));
- mm_free(win32op);
-}
-
-#endif