Copy libevent sources to contrib

To replace the libevent embedded in ntp, for OpenSSL 1.1.1 compat.

Approved by:	re (gjb)
This commit is contained in:
Ed Maste 2018-10-09 14:05:11 +00:00
commit c43e99fd14
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=339252
193 changed files with 139295 additions and 0 deletions

1849
contrib/libevent/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,231 @@
Changes in 1.4.14b-stable
o Set the VERSION_INFO correctly for 1.4.14
Changes in 1.4.14-stable
o Add a .gitignore file for the 1.4 branch. (d014edb)
o Backport evbuffer_readln(). (b04cc60 Nicholas Marriott)
o Make the evbuffer_readln backport follow the current API (c545485)
o Valgrind fix: Clear struct kevent before checking for OSX bug. (5713d5d William Ahern)
o Fix a crash when reading badly formatted resolve.conf (5b10d00 Yasuoka Masahiko)
o Fix memory-leak of signal handler array with kqueue. [backport] (01f3775)
o Update sample/signal-test.c to use newer APIs and not leak. (891765c Evan Jones)
o Correct all versions in 1.4 branch (ac0d213)
o Make evutil_make_socket_nonblocking() leave any other flags alone. (81c26ba Jardel Weyrich)
o Adjusted fcntl() retval comparison on evutil_make_socket_nonblocking(). (5f2e250 Jardel Weyrich)
o Correct a debug message in evhttp_parse_request_line (35df59e)
o Merge branch 'readln-backport' into patches-1.4 (8771d5b)
o Do not send an HTTP error when we've already closed or responded. (4fd2dd9 Pavel Plesov)
o Re-add event_siglcb; some old code _was_ still using it. :( (bd03d06)
o Make Libevent 1.4 build on win32 with Unicode enabled. (bce58d6 Brodie Thiesfield)
o Distribute nmake makefile for 1.4 (20d706d)
o do not fail while sending on http connections the client closed. (5c8b446)
o make evhttp_send() safe against terminated connections, too (01ea0c5)
o Fix a free(NULL) in min_heap.h (2458934)
o Fix memory leak when setting up priorities; reported by Alexander Drozdov (cb1a722)
o Clean up properly when adding a signal handler fails. (ae6ece0 Gilad Benjamini)
o Do not abort HTTP requests missing a reason string. (29d7b32 Pierre Phaneuf)
o Fix compile warning in http.c (906d573)
o Define _REENTRANT as needed on Solaris, elsewhere (6cbea13)
Changes in 1.4.13-stable:
o If the kernel tells us that there are a negative number of bytes to read from a socket, do not believe it. Fixes bug 2841177; found by Alexander Pronchenkov.
o Do not allocate the maximum event queue and fd array for the epoll backend at startup. Instead, start out accepting 32 events at a time, and double the queue's size when it seems that the OS is generating events faster than we're requesting them. Saves up to 512K per epoll-based event_base. Resolves bug 2839240.
o Fix compilation on Android, which forgot to define fd_mask in its sys/select.h
o Do not drop data from evbuffer when out of memory; reported by Jacek Masiulaniec
o Rename our replacement compat/sys/_time.h header to avoid build a conflict on HPUX; reported by Kathryn Hogg.
o Build kqueue.c correctly on GNU/kFreeBSD platforms. Patch pulled upstream from Debian.
o Fix a problem with excessive memory allocation when using multiple event priorities.
o When running set[ug]id, don't check the environment. Based on a patch from OpenBSD.
Changes in 1.4.12-stable:
o Try to contain degree of failure when running on a win32 version so heavily firewalled that we can't fake a socketpair.
o Fix an obscure timing-dependent, allocator-dependent crash in the evdns code.
o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC.
o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
o Fix another pair of fencepost bugs in epoll.c. [Patch from Adam Langley.]
o Do not break evdns connections to nameservers when our IP changes.
o Set truncated flag correctly in evdns server replies.
o Disable strict aliasing with GCC: our code is not compliant with it.
Changes in 1.4.11-stable:
o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
o Remove the limit on size of HTTP headers by removing static buffers.
o Fix a nasty dangling pointer bug in epoll.c that could occur after epoll_recalc(). [Patch from Kevin Springborn]
o Distribute Win32-Code/event-config.h, not ./event-config.h
Changes in 1.4.10-stable:
o clean up buffered http connection data on reset; reported by Brian O'Kelley
o bug fix and potential race condition in signal handling; from Alexander Drozdov
o rename the Solaris event ports backend to evport
o support compilation on Haiku
o fix signal processing when a signal callback delivers a signal; from Alexander Drozdov
o const-ify some arguments to evdns functions.
o off-by-one error in epoll_recalc; reported by Victor Goya
o include Doxyfile in tar ball; from Jeff Garzik
o correctly parse queries with encoded \r, \n or + characters
Changes in 1.4.9-stable:
o event_add would not return error for some backends; from Dean McNamee
o Clear the timer cache on entering the event loop; reported by Victor Chang
o Only bind the socket on connect when a local address has been provided; reported by Alejo Sanchez
o Allow setting of local port for evhttp connections to support millions of connections from a single system; from Richard Jones.
o Clear the timer cache when leaving the event loop; reported by Robin Haberkorn
o Fix a typo in setting the global event base; reported by lance.
o Fix a memory leak when reading multi-line headers
o Fix a memory leak by not running explicit close detection for server connections
Changes in 1.4.8-stable:
o Match the query in DNS replies to the query in the request; from Vsevolod Stakhov.
o Fix a merge problem in which name_from_addr returned pointers to the stack; found by Jiang Hong.
o Do not remove Accept-Encoding header
Changes in 1.4.7-stable:
o Fix a bug where headers arriving in multiple packets were not parsed; fix from Jiang Hong; test by me.
Changes in 1.4.6-stable:
o evutil.h now includes <stdarg.h> directly
o switch all uses of [v]snprintf over to evutil
o Correct handling of trailing headers in chunked replies; from Scott Lamb.
o Support multi-line HTTP headers; based on a patch from Moshe Litvin
o Reject negative Content-Length headers; anonymous bug report
o Detect CLOCK_MONOTONIC at runtime for evdns; anonymous bug report
o Fix a bug where deleting signals with the kqueue backend would cause subsequent adds to fail
o Support multiple events listening on the same signal; make signals regular events that go on the same event queue; problem report by Alexander Drozdov.
o Deal with evbuffer_read() returning -1 on EINTR|EAGAIN; from Adam Langley.
o Fix a bug in which the DNS server would incorrectly set the type of a cname reply to a.
o Fix a bug where setting the timeout on a bufferevent would take not effect if the event was already pending.
o Fix a memory leak when using signals for some event bases; reported by Alexander Drozdov.
o Add libevent.vcproj file to distribution to help with Windows build.
o Fix a problem with epoll() and reinit; problem report by Alexander Drozdov.
o Fix off-by-one errors in devpoll; from Ian Bell
o Make event_add not change any state if it fails; reported by Ian Bell.
o Do not warn on accept when errno is either EAGAIN or EINTR
Changes in 1.4.5-stable:
o Fix connection keep-alive behavior for HTTP/1.0
o Fix use of freed memory in event_reinit; pointed out by Peter Postma
o Constify struct timeval * where possible; pointed out by Forest Wilkinson
o allow min_heap_erase to be called on removed members; from liusifan.
o Rename INPUT and OUTPUT to EVRPC_INPUT and EVRPC_OUTPUT. Retain INPUT/OUTPUT aliases on on-win32 platforms for backwards compatibility.
o Do not use SO_REUSEADDR when connecting
o Fix Windows build
o Fix a bug in event_rpcgen when generated fixed-sized entries
Changes in 1.4.4-stable:
o Correct the documentation on buffer printf functions.
o Don't warn on unimplemented epoll_create(): this isn't a problem, just a reason to fall back to poll or select.
o Correctly handle timeouts larger than 35 minutes on Linux with epoll.c. This is probably a kernel defect, but we'll have to support old kernels anyway even if it gets fixed.
o Fix a potential stack corruption bug in tagging on 64-bit CPUs.
o expose bufferevent_setwatermark via header files and fix high watermark on read
o fix a bug in bufferevent read water marks and add a test for them
o introduce bufferevent_setcb and bufferevent_setfd to allow better manipulation of bufferevents
o use libevent's internal timercmp on all platforms, to avoid bugs on old platforms where timercmp(a,b,<=) is buggy.
o reduce system calls for getting current time by caching it.
o fix evhttp_bind_socket() so that multiple sockets can be bound by the same http server.
o Build test directory correctly with CPPFLAGS set.
o Fix build under Visual C++ 2005.
o Expose evhttp_accept_socket() API.
o Merge windows gettimeofday() replacement into a new evutil_gettimeofday() function.
o Fix autoconf script behavior on IRIX.
o Make sure winsock2.h include always comes before windows.h include.
Changes in 1.4.3-stable:
o include Content-Length in reply for HTTP/1.0 requests with keep-alive
o Patch from Tani Hosokawa: make some functions in http.c threadsafe.
o Do not free the kqop file descriptor in other processes, also allow it to be 0; from Andrei Nigmatulin
o make event_rpcgen.py generate code include event-config.h; reported by Sam Banks.
o make event methods static so that they are not exported; from Andrei Nigmatulin
o make RPC replies use application/octet-stream as mime type
o do not delete uninitialized timeout event in evdns
Changes in 1.4.2-rc:
o remove pending timeouts on event_base_free()
o also check EAGAIN for Solaris' event ports; from W.C.A. Wijngaards
o devpoll and evport need reinit; tested by W.C.A Wijngaards
o event_base_get_method; from Springande Ulv
o Send CRLF after each chunk in HTTP output, for compliance with RFC2626. Patch from "propanbutan". Fixes bug 1894184.
o Add a int64_t parsing function, with unit tests, so we can apply Scott Lamb's fix to allow large HTTP values.
o Use a 64-bit field to hold HTTP content-lengths. Patch from Scott Lamb.
o Allow regression code to build even without Python installed
o remove NDEBUG ifdefs from evdns.c
o update documentation of event_loop and event_base_loop; from Tani Hosokawa.
o detect integer types properly on platforms without stdint.h
o Remove "AM_MAINTAINER_MODE" declaration in configure.in: now makefiles and configure should get re-generated automatically when Makefile.am or configure.in chanes.
o do not insert event into list when evsel->add fails
Changes in 1.4.1-beta:
o free minheap on event_base_free(); from Christopher Layne
o debug cleanups in signal.c; from Christopher Layne
o provide event_base_new() that does not set the current_base global
o bufferevent_write now uses a const source argument; report from Charles Kerr
o better documentation for event_base_loopexit; from Scott Lamb.
o Make kqueue have the same behavior as other backends when a signal is caught between event_add() and event_loop(). Previously, it would catch and ignore such signals.
o Make kqueue restore signal handlers correctly when event_del() is called.
o provide event_reinit() to reintialize an event_base after fork
o small improvements to evhttp documentation
o always generate Date and Content-Length headers for HTTP/1.1 replies
o set the correct event base for HTTP close events
o New function, event_{base_}loopbreak. Like event_loopexit, it makes an event loop stop executing and return. Unlike event_loopexit, it keeps subsequent pending events from getting executed. Patch from Scott Lamb
o Removed obsoleted recalc code
o pull setters/getters out of RPC structures into a base class to which we just need to store a pointer; this reduces the memory footprint of these structures.
o fix a bug with event_rpcgen for integers
o move EV_PERSIST handling out of the event backends
o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly.
o prefix {encode,decode}_tag functions with evtag to avoid collisions
o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings. (Nick has been building with these for a while, but they might be useful to other developers.)
o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions.
o removed linger from http server socket; reported by Ilya Martynov
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
o demote most http warnings to debug messages
o Fix Solaris compilation; from Magne Mahre
o Add a "Date" header to HTTP responses, as required by HTTP 1.1.
o Support specifying the local address of an evhttp_connection using set_local_address
o Fix a memory leak in which failed HTTP connections would not free the request object
o Make adding of array members in event_rpcgen more efficient, but doubling memory allocation
o Fix a memory leak in the DNS server
o Fix compilation when DNS_USE_OPENSSL_FOR_ID is enabled
o Fix buffer size and string generation in evdns_resolve_reverse_ipv6().
o Respond to nonstandard DNS queries with "NOTIMPL" rather than by ignoring them.
o In DNS responses, the CD flag should be preserved, not the TC flag.
o Fix http.c to compile properly with USE_DEBUG; from Christopher Layne
o Handle NULL timeouts correctly on Solaris; from Trond Norbye
o Recalculate pending events properly when reallocating event array on Solaris; from Trond Norbye
o Add Doxygen documentation to header files; from Mark Heily
o Add a evdns_set_transaction_id_fn() function to override the default
transaction ID generation code.
o Add an evutil module (with header evutil.h) to implement our standard cross-platform hacks, on the theory that somebody else would like to use them too.
o Fix signals implementation on windows.
o Fix http module on windows to close sockets properly.
o Make autogen.sh script run correctly on systems where /bin/sh isn't bash. (Patch from Trond Norbye, rewritten by Hagne Mahre and then Hannah Schroeter.)
o Skip calling gettime() in timeout_process if we are not in fact waiting for any events. (Patch from Trond Norbye)
o Make test subdirectory compile under mingw.
o Fix win32 buffer.c behavior so that it is correct for sockets (which do not like ReadFile and WriteFile).
o Make the test.sh script run unit tests for the evpoll method.
o Make the entire evdns.h header enclosed in "extern C" as appropriate.
o Fix implementation of strsep on platforms that lack it
o Fix implementation of getaddrinfo on platforms that lack it; mainly, this will make Windows http.c work better. Original patch by Lubomir Marinov.
o Fix evport implementation: port_disassociate called on unassociated events resulting in bogus errors; more efficient memory management; from Trond Norbye and Prakash Sangappa
o support for hooks on rpc input and output; can be used to implement rpc independent processing such as compression or authentication.
o use a min heap instead of a red-black tree for timeouts; as a result finding the min is a O(1) operation now; from Maxim Yegorushkin
o associate an event base with an rpc pool
o added two additional libraries: libevent_core and libevent_extra in addition to the regular libevent. libevent_core contains only the event core whereas libevent_extra contains dns, http and rpc support
o Begin using libtool's library versioning support correctly. If we don't mess up, this will more or less guarantee binaries linked against old versions of libevent continue working when we make changes to libevent that do not break backward compatibility.
o Fix evhttp.h compilation when TAILQ_ENTRY is not defined.
o Small code cleanups in epoll_dispatch().
o Increase the maximum number of addresses read from a packet in evdns to 32.
o Remove support for the rtsig method: it hasn't compiled for a while, and nobody seems to miss it very much. Let us know if there's a good reason to put it back in.
o Rename the "class" field in evdns_server_request to dns_question_class, so that it won't break compilation under C++. Use a macro so that old code won't break. Mark the macro as deprecated.
o Fix DNS unit tests so that having a DNS server with broken IPv6 support is no longer cause for aborting the unit tests.
o Make event_base_free() succeed even if there are pending non-internal events on a base. This may still leak memory and fds, but at least it no longer crashes.
o Post-process the config.h file into a new, installed event-config.h file that we can install, and whose macros will be safe to include in header files.
o Remove the long-deprecated acconfig.h file.
o Do not require #include <sys/types.h> before #include <event.h>.
o Add new evutil_timer* functions to wrap (or replace) the regular timeval manipulation functions.
o Fix many build issues when using the Microsoft C compiler.
o Remove a bash-ism in autogen.sh
o When calling event_del on a signal, restore the signal handler's previous value rather than setting it to SIG_DFL. Patch from Christopher Layne.
o Make the logic for active events work better with internal events; patch from Christopher Layne.
o We do not need to specially remove a timeout before calling event_del; patch from Christopher Layne.

File diff suppressed because it is too large Load Diff

257
contrib/libevent/Doxyfile Normal file
View File

@ -0,0 +1,257 @@
# Doxyfile 1.5.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = libevent
# Place all output under 'doxygen/'
OUTPUT_DIRECTORY = doxygen/
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like the Qt-style comments (thus requiring an
# explicit @brief command for a brief description.
JAVADOC_AUTOBRIEF = YES
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically
# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = YES
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH = include/
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = \
include/event2/buffer.h \
include/event2/buffer_compat.h \
include/event2/bufferevent.h \
include/event2/bufferevent_compat.h \
include/event2/bufferevent_ssl.h \
include/event2/dns.h \
include/event2/dns_compat.h \
include/event2/event.h \
include/event2/event_compat.h \
include/event2/http.h \
include/event2/http_compat.h \
include/event2/listener.h \
include/event2/rpc.h \
include/event2/rpc_compat.h \
include/event2/tag.h \
include/event2/tag_compat.h \
include/event2/thread.h \
include/event2/util.h
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = NO
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
# then it will generate one additional man file for each entity
# documented in the real man page(s). These additional files
# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
MAN_LINKS = YES
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
PREDEFINED = TAILQ_ENTRY RB_ENTRY EVENT_DEFINED_TQENTRY_ EVENT_IN_DOXYGEN_
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all function-like macros that are alone
# on a line, have an all uppercase name, and do not end with a semicolon. Such
# function macros are typically used for boiler-plate code, and will confuse
# the parser if not removed.
SKIP_FUNCTION_MACROS = YES

99
contrib/libevent/LICENSE Normal file
View File

@ -0,0 +1,99 @@
Libevent is available for use under the following license, commonly known
as the 3-clause (or "modified") BSD license:
==============================
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.
==============================
Portions of Libevent are based on works by others, also made available by
them under the three-clause BSD license above. The copyright notices are
available in the corresponding source files; the license is as above. Here's
a list:
log.c:
Copyright (c) 2000 Dug Song <dugsong@monkey.org>
Copyright (c) 1993 The Regents of the University of California.
strlcpy.c:
Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
win32select.c:
Copyright (c) 2003 Michael A. Davis <mike@datanerds.net>
evport.c:
Copyright (c) 2007 Sun Microsystems
ht-internal.h:
Copyright (c) 2002 Christopher Clark
minheap-internal.h:
Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
==============================
The arc4module is available under the following, sometimes called the
"OpenBSD" license:
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.
==============================
The Windows timer code is based on code from libutp, which is
distributed under this license, sometimes called the "MIT" 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.

View File

@ -0,0 +1,311 @@
# Makefile.am for libevent
# Copyright 2000-2007 Niels Provos
# Copyright 2007-2012 Niels Provos and Nick Mathewson
#
# See LICENSE for copying information.
# 'foreign' means that we're not enforcing GNU package rules strictly.
# '1.9' means that we need automake 1.9 or later (and we do).
AUTOMAKE_OPTIONS = foreign 1.9 subdir-objects
ACLOCAL_AMFLAGS = -I m4
# This is the "Release" of the Libevent ABI. It takes precedence over
# the VERSION_INFO, so that two versions of Libevent with the same
# "Release" are never binary-compatible.
#
# This number incremented once for the 2.0 release candidate, and
# will increment for each series until we revise our interfaces enough
# that we can seriously expect ABI compatibility between series.
#
RELEASE = -release 2.1
# This is the version info for the libevent binary API. It has three
# numbers:
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
# API are we supplying?
# Age -- How many previous binary API versions do we also
# support?
#
# To increment a VERSION_INFO (current:revision:age):
# If the ABI didn't change:
# Return (current:revision+1:age)
# If the ABI changed, but it's backward-compatible:
# Return (current+1:0:age+1)
# If the ABI changed and it isn't backward-compatible:
# Return (current+1:0:0)
#
# Once an RC is out, DO NOT MAKE ANY ABI-BREAKING CHANGES IN THAT SERIES
# UNLESS YOU REALLY REALLY HAVE TO.
VERSION_INFO = 6:2:0
# History: RELEASE VERSION_INFO
# 2.0.1-alpha -- 2.0 1:0:0
# 2.0.2-alpha -- 2:0:0
# 2.0.3-alpha -- 2:0:0 (should have incremented; didn't.)
# 2.0.4-alpha -- 3:0:0
# 2.0.5-beta -- 4:0:0
# 2.0.6-rc -- 2.0 2:0:0
# 2.0.7-rc -- 2.0 3:0:1
# 2.0.8-rc -- 2.0 4:0:2
# 2.0.9-rc -- 2.0 5:0:0 (ABI changed slightly)
# 2.0.10-stable-- 2.0 5:1:0 (No ABI change)
# 2.0.11-stable-- 2.0 6:0:1 (ABI changed, backward-compatible)
# 2.0.12-stable-- 2.0 6:1:1 (No ABI change)
# 2.0.13-stable-- 2.0 6:2:1 (No ABI change)
# 2.0.14-stable-- 2.0 6:3:1 (No ABI change)
# 2.0.15-stable-- 2.0 6:3:1 (Forgot to update :( )
# 2.0.16-stable-- 2.0 6:4:1 (No ABI change)
# 2.0.17-stable-- 2.0 6:5:1 (No ABI change)
# 2.0.18-stable-- 2.0 6:6:1 (No ABI change)
# 2.0.19-stable-- 2.0 6:7:1 (No ABI change)
# 2.0.20-stable-- 2.0 6:8:1 (No ABI change)
# 2.0.21-stable-- 2.0 6:9:1 (No ABI change)
#
# For Libevent 2.1:
# 2.1.1-alpha -- 2.1 1:0:0
# 2.1.2-alpha -- 2.1 1:0:0 (should have been 2:0:1)
# 2.1.3-alpha -- 2.1 3:0:0 (ABI changed slightly)
# 2.1.4-alpha -- 2.1 4:0:0 (ABI changed slightly)
# 2.1.5-beta -- 2.1 5:0:0 (ABI changed slightly)
# 2.1.6-beta -- 2.1 6:0:0 (ABI changed slightly)
# 2.1.7-beta -- 2.1 6:1:0 (ABI changed slightly)
# 2.1.8-stable-- 2.1 6:2:0 (ABI changed slightly)
# ABI version history for this package effectively restarts every time
# we change RELEASE. Version 1.4.x had RELEASE of 1.4.
#
# Ideally, we would not be using RELEASE at all; instead we could just
# use the VERSION_INFO field to label our backward-incompatible ABI
# changes, and those would be few and far between. Unfortunately,
# Libevent still exposes far too many volatile structures in its
# headers, so we pretty much have to assume that most development
# series will break ABI compatibility. For now, it's simplest just to
# keep incrementing the RELEASE between series and resetting VERSION_INFO.
#
# Eventually, when we get to the point where the structures in the
# headers are all non-changing (or not there at all!), we can shift to
# a more normal worldview where backward-incompatible ABI changes are
# nice and rare. For the next couple of years, though, 'struct event'
# is user-visible, and so we can pretty much guarantee that release
# series won't be binary-compatible.
if INSTALL_LIBEVENT
dist_bin_SCRIPTS = event_rpcgen.py
endif
pkgconfigdir=$(libdir)/pkgconfig
LIBEVENT_PKGCONFIG=libevent.pc libevent_core.pc libevent_extra.pc
# These sources are conditionally added by configure.ac or conditionally
# included from other files.
PLATFORM_DEPENDENT_SRC = \
arc4random.c \
epoll_sub.c
EXTRA_DIST = \
ChangeLog-1.4 \
ChangeLog-2.0 \
Doxyfile \
LICENSE \
Makefile.nmake test/Makefile.nmake \
autogen.sh \
event_rpcgen.py \
libevent.pc.in \
make-event-config.sed \
whatsnew-2.0.txt \
whatsnew-2.1.txt \
$(PLATFORM_DEPENDENT_SRC)
LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la
if PTHREADS
LIBEVENT_LIBS_LA += libevent_pthreads.la
LIBEVENT_PKGCONFIG += libevent_pthreads.pc
endif
if OPENSSL
LIBEVENT_LIBS_LA += libevent_openssl.la
LIBEVENT_PKGCONFIG += libevent_openssl.pc
endif
if INSTALL_LIBEVENT
lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
pkgconfig_DATA = $(LIBEVENT_PKGCONFIG)
else
noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA)
endif
EXTRA_SOURCE=
noinst_HEADERS=
noinst_PROGRAMS=
EXTRA_PROGRAMS=
CLEANFILES=
DISTCLEANFILES=
BUILT_SOURCES =
include include/include.am
include sample/include.am
include test/include.am
if BUILD_WIN32
SYS_LIBS = -lws2_32 -lshell32 -ladvapi32
SYS_SRC = win32select.c buffer_iocp.c event_iocp.c \
bufferevent_async.c
SYS_INCLUDES = -IWIN32-Code -IWIN32-Code/nmake
if THREADS
SYS_SRC += evthread_win32.c
endif
else
SYS_LIBS =
SYS_SRC =
SYS_INCLUDES =
endif
if STRLCPY_IMPL
SYS_SRC += strlcpy.c
endif
if SELECT_BACKEND
SYS_SRC += select.c
endif
if POLL_BACKEND
SYS_SRC += poll.c
endif
if DEVPOLL_BACKEND
SYS_SRC += devpoll.c
endif
if KQUEUE_BACKEND
SYS_SRC += kqueue.c
endif
if EPOLL_BACKEND
SYS_SRC += epoll.c
endif
if EVPORT_BACKEND
SYS_SRC += evport.c
endif
if SIGNAL_SUPPORT
SYS_SRC += signal.c
endif
BUILT_SOURCES += include/event2/event-config.h
include/event2/event-config.h: config.h make-event-config.sed
$(AM_V_GEN)test -d include/event2 || $(MKDIR_P) include/event2
$(AM_V_at)$(SED) -f $(srcdir)/make-event-config.sed < config.h > $@T
$(AM_V_at)mv -f $@T $@
CORE_SRC = \
buffer.c \
bufferevent.c \
bufferevent_filter.c \
bufferevent_pair.c \
bufferevent_ratelim.c \
bufferevent_sock.c \
event.c \
evmap.c \
evthread.c \
evutil.c \
evutil_rand.c \
evutil_time.c \
listener.c \
log.c \
$(SYS_SRC)
EXTRAS_SRC = \
evdns.c \
event_tagging.c \
evrpc.c \
http.c
if BUILD_WITH_NO_UNDEFINED
NO_UNDEFINED = -no-undefined
MAYBE_CORE = libevent_core.la
else
NO_UNDEFINED =
MAYBE_CORE =
endif
GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED)
libevent_la_SOURCES = $(CORE_SRC) $(EXTRAS_SRC)
libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
libevent_la_LDFLAGS = $(GENERIC_LDFLAGS)
libevent_core_la_SOURCES = $(CORE_SRC)
libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
libevent_core_la_LDFLAGS = $(GENERIC_LDFLAGS)
if PTHREADS
libevent_pthreads_la_SOURCES = evthread_pthread.c
libevent_pthreads_la_LIBADD = $(MAYBE_CORE)
libevent_pthreads_la_LDFLAGS = $(GENERIC_LDFLAGS)
endif
libevent_extra_la_SOURCES = $(EXTRAS_SRC)
libevent_extra_la_LIBADD = $(MAYBE_CORE) $(SYS_LIBS)
libevent_extra_la_LDFLAGS = $(GENERIC_LDFLAGS)
if OPENSSL
libevent_openssl_la_SOURCES = bufferevent_openssl.c
libevent_openssl_la_LIBADD = $(MAYBE_CORE) $(OPENSSL_LIBS)
libevent_openssl_la_LDFLAGS = $(GENERIC_LDFLAGS)
libevent_openssl_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
endif
noinst_HEADERS += \
WIN32-Code/nmake/evconfig-private.h \
WIN32-Code/nmake/event2/event-config.h \
WIN32-Code/tree.h \
bufferevent-internal.h \
changelist-internal.h \
compat/sys/queue.h \
defer-internal.h \
epolltable-internal.h \
evbuffer-internal.h \
evconfig-private.h \
event-internal.h \
evmap-internal.h \
evrpc-internal.h \
evsignal-internal.h \
evthread-internal.h \
ht-internal.h \
http-internal.h \
iocp-internal.h \
ipv6-internal.h \
kqueue-internal.h \
log-internal.h \
minheap-internal.h \
mm-internal.h \
ratelim-internal.h \
ratelim-internal.h \
strlcpy-internal.h \
time-internal.h \
util-internal.h \
openssl-compat.h
EVENT1_HDRS = \
include/evdns.h \
include/event.h \
include/evhttp.h \
include/evrpc.h \
include/evutil.h
if INSTALL_LIBEVENT
include_HEADERS = $(EVENT1_HDRS)
else
noinst_HEADERS += $(EVENT1_HDRS)
endif
AM_CPPFLAGS = -I$(srcdir)/compat -I$(srcdir)/include -I./include $(SYS_INCLUDES)
verify: check
doxygen: FORCE
doxygen $(srcdir)/Doxyfile
FORCE:
DISTCLEANFILES += *~ libevent.pc libevent_core.pc libevent_extra.pc ./include/event2/event-config.h

2748
contrib/libevent/Makefile.in Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
# WATCH OUT! This makefile is a work in progress. -*- makefile -*-
#
# I'm not very knowledgeable about MSVC and nmake beyond their most basic
# aspects. If anything here looks wrong to you, please let me know.
# If OPENSSL_DIR is not set, builds without OpenSSL support. If you want
# OpenSSL support, you can set the OPENSSL_DIR variable to where you
# installed OpenSSL. This can be done in the environment:
# set OPENSSL_DIR=c:\openssl
# Or on the nmake command line:
# nmake OPENSSL_DIR=C:\openssl -f Makefile.nmake
# Or by uncommenting the following line here in the makefile...
# OPENSSL_DIR=c:\openssl
!IFDEF OPENSSL_DIR
SSL_CFLAGS=/I$(OPENSSL_DIR)\include /DEVENT__HAVE_OPENSSL
!ELSE
SSL_CFLAGS=
!ENDIF
# Needed for correctness
CFLAGS=/IWIN32-Code /IWIN32-Code/nmake /Iinclude /Icompat /DHAVE_CONFIG_H /I. $(SSL_CFLAGS)
# For optimization and warnings
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
# XXXX have a debug mode
LIBFLAGS=/nologo
CORE_OBJS=event.obj buffer.obj bufferevent.obj bufferevent_sock.obj \
bufferevent_pair.obj listener.obj evmap.obj log.obj evutil.obj \
strlcpy.obj signal.obj bufferevent_filter.obj evthread.obj \
bufferevent_ratelim.obj evutil_rand.obj evutil_time.obj
WIN_OBJS=win32select.obj evthread_win32.obj buffer_iocp.obj \
event_iocp.obj bufferevent_async.obj
EXTRA_OBJS=event_tagging.obj http.obj evdns.obj evrpc.obj
!IFDEF OPENSSL_DIR
SSL_OBJS=bufferevent_openssl.obj
SSL_LIBS=libevent_openssl.lib
!ELSE
SSL_OBJS=
SSL_LIBS=
!ENDIF
ALL_OBJS=$(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS) $(SSL_OBJS)
STATIC_LIBS=libevent_core.lib libevent_extras.lib libevent.lib $(SSL_LIBS)
all: static_libs tests
static_libs: $(STATIC_LIBS)
libevent_core.lib: $(CORE_OBJS) $(WIN_OBJS)
lib $(LIBFLAGS) $(CORE_OBJS) $(WIN_OBJS) /out:libevent_core.lib
libevent_extras.lib: $(EXTRA_OBJS)
lib $(LIBFLAGS) $(EXTRA_OBJS) /out:libevent_extras.lib
libevent.lib: $(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS)
lib $(LIBFLAGS) $(CORE_OBJS) $(EXTRA_OBJS) $(WIN_OBJS) /out:libevent.lib
libevent_openssl.lib: $(SSL_OBJS)
lib $(LIBFLAGS) $(SSL_OBJS) /out:libevent_openssl.lib
clean:
del $(ALL_OBJS)
del $(STATIC_LIBS)
cd test
$(MAKE) /F Makefile.nmake clean
cd ..
tests:
cd test
!IFDEF OPENSSL_DIR
$(MAKE) OPENSSL_DIR=$(OPENSSL_DIR) /F Makefile.nmake
!ELSE
$(MAKE) /F Makefile.nmake
!ENDIF
cd ..

View File

@ -0,0 +1,6 @@
#if !defined(EVENT_EVCONFIG__PRIVATE_H_) && !defined(__MINGW32__)
#define EVENT_EVCONFIG__PRIVATE_H_
/* Nothing to see here. Move along. */
#endif

View File

@ -0,0 +1,360 @@
/* 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 0x02010800
/* 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.8-stable"
/* 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

View File

@ -0,0 +1,677 @@
/* $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_ */

1161
contrib/libevent/aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,556 @@
/* 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 <wincrypt.h>
#include <process.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 inline unsigned char arc4_getbyte(void);
static inline void
arc4_init(void)
{
int n;
for (n = 0; n < 256; n++)
rs.s[n] = n;
rs.i = 0;
rs.j = 0;
}
static inline 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 inline 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 inline 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

22
contrib/libevent/autogen.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
MAKE=make
if command -v gmake >/dev/null 2>/dev/null; then
MAKE=gmake
fi
$MAKE maintainer-clean >/dev/null 2>/dev/null
if [ -x "`which autoreconf 2>/dev/null`" ] ; then
exec autoreconf -ivf
fi
LIBTOOLIZE=libtoolize
SYSNAME=`uname`
if [ "x$SYSNAME" = "xDarwin" ] ; then
LIBTOOLIZE=glibtoolize
fi
aclocal -I m4 && \
autoheader && \
$LIBTOOLIZE && \
autoconf && \
automake --add-missing --force-missing --copy

3447
contrib/libevent/buffer.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,326 @@
/*
* 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);
}

View File

@ -0,0 +1,482 @@
/*
* 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;
struct evdns_getaddrinfo_request *dns_request;
};
/** 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,686 @@
/*
* 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;
}
}

View File

@ -0,0 +1,623 @@
/*
* 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_inbuf_cb(struct evbuffer *buf,
const struct evbuffer_cb_info *cbinfo, void *arg);
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 inbuf to notice somebory removes data */
struct evbuffer_cb_entry *inbuf_cb;
/** 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->inbuf_cb = evbuffer_add_cb(downcast(bufev_f)->input,
bufferevent_filtered_inbuf_cb, bufev_f);
evbuffer_cb_clear_flags(downcast(bufev_f)->input, bufev_f->inbuf_cb,
EVBUFFER_CB_ENABLED);
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);
if (bevf->inbuf_cb)
evbuffer_remove_cb_entry(bev->input, bevf->inbuf_cb);
if (bevf->outbuf_cb)
evbuffer_remove_cb_entry(bev->output, bevf->outbuf_cb);
}
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_clear_flags(bufev->output, bevf->outbuf_cb,
EVBUFFER_CB_ENABLED);
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);
}
}
static void
be_filter_read_nolock_(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;
// 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);
if (evbuffer_get_length(underlying->input) > 0 &&
be_readbuf_full(bevf, state)) {
/* data left in underlying buffer and filter input buffer
* hit its read high watermark.
* Schedule callback to avoid data gets stuck in underlying
* input buffer.
*/
evbuffer_cb_set_flags(bufev->input, bevf->inbuf_cb,
EVBUFFER_CB_ENABLED);
}
}
}
}
/* Called when the size of our inbuf changes. */
static void
bufferevent_filtered_inbuf_cb(struct evbuffer *buf,
const struct evbuffer_cb_info *cbinfo, void *arg)
{
struct bufferevent_filtered *bevf = arg;
enum bufferevent_flush_mode state;
struct bufferevent *bev = downcast(bevf);
BEV_LOCK(bev);
if (bevf->got_eof)
state = BEV_FINISHED;
else
state = BEV_NORMAL;
if (!be_readbuf_full(bevf, state)) {
/* opportunity to read data which was left in underlying
* input buffer because filter input buffer hit read
* high watermark.
*/
evbuffer_cb_clear_flags(bev->input, bevf->inbuf_cb,
EVBUFFER_CB_ENABLED);
if (evbuffer_get_length(bevf->underlying->input) > 0)
be_filter_read_nolock_(bevf->underlying, bevf);
}
BEV_UNLOCK(bev);
}
/* Called when the underlying socket has read. */
static void
be_filter_readcb(struct bufferevent *underlying, void *me_)
{
struct bufferevent_filtered *bevf = me_;
struct bufferevent *bev = downcast(bevf);
BEV_LOCK(bev);
be_filter_read_nolock_(underlying, me_);
BEV_UNLOCK(bev);
}
/* 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,365 @@
/*
* 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) {
short what = BEV_EVENT_EOF;
if (iotype & EV_READ)
what |= BEV_EVENT_WRITING;
if (iotype & EV_WRITE)
what |= BEV_EVENT_READING;
bufferevent_run_eventcb_(partner, what, 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 */
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,719 @@
/*
* 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;
if (EVUTIL_ERR_CONNECT_REFUSED(err)) {
bufev_p->connection_refused = 1;
goto done;
}
/* 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;
bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
} else {
/* The connect failed already. How very BSD of it. */
result = 0;
bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
bufferevent_disable(bev, EV_WRITE|EV_READ);
}
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);
bev_p->dns_request = NULL;
if (result == EVUTIL_EAI_CANCEL) {
bev_p->dns_error = result;
bufferevent_decref_and_unlock_(bev);
return;
}
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;
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);
bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname,
portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev);
BEV_UNLOCK(bev);
return 0;
}
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);
evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
}
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)
{
struct bufferevent_private *bufev_p =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
BEV_LOCK(bufev);
EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket);
event_del(&bufev->ev_read);
event_del(&bufev->ev_write);
evbuffer_unfreeze(bufev->input, 0);
evbuffer_unfreeze(bufev->output, 1);
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);
evutil_getaddrinfo_cancel_async_(bufev_p->dns_request);
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;
}
}

View File

@ -0,0 +1,102 @@
/*
* 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

View File

@ -0,0 +1,488 @@
/* $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__ */

347
contrib/libevent/compile Executable file
View File

@ -0,0 +1,347 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

1421
contrib/libevent/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,529 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if libevent should build without support for a debug mode */
#undef DISABLE_DEBUG_MODE
/* Define if libevent should not allow replacing the mm functions */
#undef DISABLE_MM_REPLACEMENT
/* Define if libevent should not be compiled with thread support */
#undef DISABLE_THREAD_SUPPORT
/* Define to 1 if you have the `accept4' function. */
#undef HAVE_ACCEPT4
/* Define to 1 if you have the `arc4random' function. */
#undef HAVE_ARC4RANDOM
/* Define to 1 if you have the `arc4random_buf' function. */
#undef HAVE_ARC4RANDOM_BUF
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the declaration of `CTL_KERN', and to 0 if you
don't. */
#undef HAVE_DECL_CTL_KERN
/* Define to 1 if you have the declaration of `KERN_ARND', and to 0 if you
don't. */
#undef HAVE_DECL_KERN_ARND
/* Define to 1 if you have the declaration of `KERN_RANDOM', and to 0 if you
don't. */
#undef HAVE_DECL_KERN_RANDOM
/* Define to 1 if you have the declaration of `RANDOM_UUID', and to 0 if you
don't. */
#undef HAVE_DECL_RANDOM_UUID
/* Define if /dev/poll is available */
#undef HAVE_DEVPOLL
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define if your system supports the epoll system calls */
#undef HAVE_EPOLL
/* Define to 1 if you have the `epoll_create1' function. */
#undef HAVE_EPOLL_CREATE1
/* Define to 1 if you have the `epoll_ctl' function. */
#undef HAVE_EPOLL_CTL
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
/* Define to 1 if you have ERR_remove_thread_stat(). */
#undef HAVE_ERR_REMOVE_THREAD_STATE
/* Define to 1 if you have the `eventfd' function. */
#undef HAVE_EVENTFD
/* Define if your system supports event ports */
#undef HAVE_EVENT_PORTS
/* Define to 1 if you have the `fcntl' function. */
#undef HAVE_FCNTL
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if the system has the type `fd_mask'. */
#undef HAVE_FD_MASK
/* Do we have getaddrinfo()? */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getegid' function. */
#undef HAVE_GETEGID
/* Define to 1 if you have the `geteuid' function. */
#undef HAVE_GETEUID
/* Define this if you have any gethostbyname_r() */
#undef HAVE_GETHOSTBYNAME_R
/* Define this if gethostbyname_r takes 3 arguments */
#undef HAVE_GETHOSTBYNAME_R_3_ARG
/* Define this if gethostbyname_r takes 5 arguments */
#undef HAVE_GETHOSTBYNAME_R_5_ARG
/* Define this if gethostbyname_r takes 6 arguments */
#undef HAVE_GETHOSTBYNAME_R_6_ARG
/* Define to 1 if you have the `getifaddrs' function. */
#undef HAVE_GETIFADDRS
/* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO
/* Define to 1 if you have the `getprotobynumber' function. */
#undef HAVE_GETPROTOBYNUMBER
/* Define to 1 if you have the `getservbyname' function. */
#undef HAVE_GETSERVBYNAME
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the <ifaddrs.h> header file. */
#undef HAVE_IFADDRS_H
/* Define to 1 if you have the `inet_ntop' function. */
#undef HAVE_INET_NTOP
/* Define to 1 if you have the `inet_pton' function. */
#undef HAVE_INET_PTON
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `issetugid' function. */
#undef HAVE_ISSETUGID
/* Define to 1 if you have the `kqueue' function. */
#undef HAVE_KQUEUE
/* Define if the system has zlib */
#undef HAVE_LIBZ
/* Define to 1 if you have the `mach_absolute_time' function. */
#undef HAVE_MACH_ABSOLUTE_TIME
/* Define to 1 if you have the <mach/mach_time.h> header file. */
#undef HAVE_MACH_MACH_TIME_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mmap' function. */
#undef HAVE_MMAP
/* Define to 1 if you have the `nanosleep' function. */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <netinet/in6.h> header file. */
#undef HAVE_NETINET_IN6_H
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
/* Define to 1 if you have the <netinet/tcp.h> header file. */
#undef HAVE_NETINET_TCP_H
/* Define if the system has openssl */
#undef HAVE_OPENSSL
/* Define to 1 if you have the `pipe' function. */
#undef HAVE_PIPE
/* Define to 1 if you have the `pipe2' function. */
#undef HAVE_PIPE2
/* Define to 1 if you have the `poll' function. */
#undef HAVE_POLL
/* Define to 1 if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define to 1 if you have the `port_create' function. */
#undef HAVE_PORT_CREATE
/* Define to 1 if you have the <port.h> header file. */
#undef HAVE_PORT_H
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define if we have pthreads on this system */
#undef HAVE_PTHREADS
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if the system has the type `sa_family_t'. */
#undef HAVE_SA_FAMILY_T
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `sendfile' function. */
#undef HAVE_SENDFILE
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define if F_SETFD is defined in <fcntl.h> */
#undef HAVE_SETFD
/* Define to 1 if you have the `setrlimit' function. */
#undef HAVE_SETRLIMIT
/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION
/* Define to 1 if you have the `signal' function. */
#undef HAVE_SIGNAL
/* Define to 1 if you have the `splice' function. */
#undef HAVE_SPLICE
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if you have the `strtok_r' function. */
#undef HAVE_STRTOK_R
/* Define to 1 if you have the `strtoll' function. */
#undef HAVE_STRTOLL
/* Define to 1 if the system has the type `struct addrinfo'. */
#undef HAVE_STRUCT_ADDRINFO
/* Define to 1 if the system has the type `struct in6_addr'. */
#undef HAVE_STRUCT_IN6_ADDR
/* Define to 1 if `s6_addr16' is a member of `struct in6_addr'. */
#undef HAVE_STRUCT_IN6_ADDR_S6_ADDR16
/* Define to 1 if `s6_addr32' is a member of `struct in6_addr'. */
#undef HAVE_STRUCT_IN6_ADDR_S6_ADDR32
/* Define to 1 if the system has the type `struct sockaddr_in6'. */
#undef HAVE_STRUCT_SOCKADDR_IN6
/* Define to 1 if `sin6_len' is a member of `struct sockaddr_in6'. */
#undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
/* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */
#undef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE
/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
/* Define to 1 if the system has the type `struct so_linger'. */
#undef HAVE_STRUCT_SO_LINGER
/* Define to 1 if you have the `sysctl' function. */
#undef HAVE_SYSCTL
/* Define to 1 if you have the <sys/devpoll.h> header file. */
#undef HAVE_SYS_DEVPOLL_H
/* Define to 1 if you have the <sys/epoll.h> header file. */
#undef HAVE_SYS_EPOLL_H
/* Define to 1 if you have the <sys/eventfd.h> header file. */
#undef HAVE_SYS_EVENTFD_H
/* Define to 1 if you have the <sys/event.h> header file. */
#undef HAVE_SYS_EVENT_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#undef HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the <sys/queue.h> header file. */
#undef HAVE_SYS_QUEUE_H
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/sendfile.h> header file. */
#undef HAVE_SYS_SENDFILE_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/sysctl.h> header file. */
#undef HAVE_SYS_SYSCTL_H
/* Define to 1 if you have the <sys/timerfd.h> header file. */
#undef HAVE_SYS_TIMERFD_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
#undef HAVE_TAILQFOREACH
/* Define if timeradd is defined in <sys/time.h> */
#undef HAVE_TIMERADD
/* Define if timerclear is defined in <sys/time.h> */
#undef HAVE_TIMERCLEAR
/* Define if timercmp is defined in <sys/time.h> */
#undef HAVE_TIMERCMP
/* Define to 1 if you have the `timerfd_create' function. */
#undef HAVE_TIMERFD_CREATE
/* Define if timerisset is defined in <sys/time.h> */
#undef HAVE_TIMERISSET
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if the system has the type `uint32_t'. */
#undef HAVE_UINT32_T
/* Define to 1 if the system has the type `uint64_t'. */
#undef HAVE_UINT64_T
/* Define to 1 if the system has the type `uint8_t'. */
#undef HAVE_UINT8_T
/* Define to 1 if the system has the type `uintptr_t'. */
#undef HAVE_UINTPTR_T
/* Define to 1 if you have the `umask' function. */
#undef HAVE_UMASK
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the `usleep' function. */
#undef HAVE_USLEEP
/* Define to 1 if you have the `vasprintf' function. */
#undef HAVE_VASPRINTF
/* Define if waitpid() supports WNOWAIT */
#undef HAVE_WAITPID_WITH_WNOWAIT
/* Define if kqueue works correctly with pipes */
#undef HAVE_WORKING_KQUEUE
/* Define to 1 if you have the <zlib.h> header file. */
#undef HAVE_ZLIB_H
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Numeric representation of the version */
#undef NUMERIC_VERSION
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
/* The size of `off_t', as computed by sizeof. */
#undef SIZEOF_OFF_T
/* The size of `pthread_t', as computed by sizeof. */
#undef SIZEOF_PTHREAD_T
/* The size of `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* The size of `size_t', as computed by sizeof. */
#undef SIZEOF_SIZE_T
/* The size of `void *', as computed by sizeof. */
#undef SIZEOF_VOID_P
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Version number of package */
#undef VERSION
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to 1 if on MINIX. */
#undef _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#undef _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE
/* Define to appropriate substitue if compiler doesnt have __func__ */
#undef __func__
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* Define to unsigned int if you dont have it */
#undef socklen_t
/* Define to `int' if <sys/types.h> does not define. */
#undef ssize_t

1807
contrib/libevent/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

18613
contrib/libevent/configure vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,947 @@
dnl Copyright 2000-2007 Niels Provos
dnl Copyright 2007-2012 Niels Provos and Nick Mathewson
dnl
dnl See LICENSE for copying information.
dnl
dnl Original version Dug Song <dugsong@monkey.org>
AC_INIT(libevent,2.1.8-stable)
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(event.c)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE
dnl AM_SILENT_RULES req. automake 1.11. [no] defaults V=1
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_CONFIG_HEADERS(config.h evconfig-private.h:evconfig-private.h.in)
AC_DEFINE(NUMERIC_VERSION, 0x02010800, [Numeric representation of the version])
dnl Initialize prefix.
if test "$prefix" = "NONE"; then
prefix="/usr/local"
fi
dnl Try and get a full POSIX environment on obscure systems
ifdef([AC_USE_SYSTEM_EXTENSIONS], [
AC_USE_SYSTEM_EXTENSIONS
], [
AC_AIX
AC_GNU_SOURCE
AC_MINIX
])
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
dnl the 'build' machine is where we run configure and compile
dnl the 'host' machine is where the resulting stuff runs.
#case "$host_os" in
#
# osf5*)
# CFLAGS="$CFLAGS -D_OSF_SOURCE"
# ;;
#esac
dnl Checks for programs.
AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LN_S
# AC_PROG_MKDIR_P - $(MKDIR_P) should be defined by AM_INIT_AUTOMAKE
# AC_PROG_SED is only available in Autoconf >= 2.59b; workaround for older
# versions
ifdef([AC_PROG_SED], [AC_PROG_SED], [
AC_CHECK_PROGS(SED, [gsed sed])
])
AC_PROG_GCC_TRADITIONAL
# We need to test for at least gcc 2.95 here, because older versions don't
# have -fno-strict-aliasing
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
#error
#endif])], have_gcc295=yes, have_gcc295=no)
if test "$GCC" = "yes" ; then
# Enable many gcc warnings by default...
CFLAGS="$CFLAGS -Wall"
# And disable the strict-aliasing optimization, since it breaks
# our sockaddr-handling code in strange ways.
if test x$have_gcc295 = xyes; then
CFLAGS="$CFLAGS -fno-strict-aliasing"
fi
fi
# OS X Lion started deprecating the system openssl. Let's just disable
# all deprecation warnings on OS X; but do so only for gcc...
if test "$GCC" = "yes" ; then
case "$host_os" in
darwin*)
CFLAGS="$CFLAGS -Wno-deprecated-declarations"
;;
esac
fi
AC_ARG_ENABLE(gcc-warnings,
AS_HELP_STRING(--disable-gcc-warnings, disable verbose warnings with GCC))
AC_ARG_ENABLE(gcc-hardening,
AS_HELP_STRING(--enable-gcc-hardening, enable compiler security checks),
[if test x$enableval = xyes; then
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all"
CFLAGS="$CFLAGS -fwrapv -fPIE -Wstack-protector"
CFLAGS="$CFLAGS --param ssp-buffer-size=1"
fi])
AC_ARG_ENABLE(thread-support,
AS_HELP_STRING(--disable-thread-support, disable support for threading),
[], [enable_thread_support=yes])
AC_ARG_ENABLE(malloc-replacement,
AS_HELP_STRING(--disable-malloc-replacement, disable support for replacing the memory mgt functions),
[], [enable_malloc_replacement=yes])
AC_ARG_ENABLE(openssl,
AS_HELP_STRING(--disable-openssl, disable support for openssl encryption),
[], [enable_openssl=yes])
AC_ARG_ENABLE(debug-mode,
AS_HELP_STRING(--disable-debug-mode, disable support for running in debug mode),
[], [enable_debug_mode=yes])
AC_ARG_ENABLE([libevent-install],
AS_HELP_STRING([--disable-libevent-install, disable installation of libevent]),
[], [enable_libevent_install=yes])
AC_ARG_ENABLE([libevent-regress],
AS_HELP_STRING([--disable-libevent-regress, skip regress in make check]),
[], [enable_libevent_regress=yes])
AC_ARG_ENABLE([samples],
AS_HELP_STRING([--disable-samples, skip building of sample programs]),
[], [enable_samples=yes])
AC_ARG_ENABLE([function-sections],
AS_HELP_STRING([--enable-function-sections, make static library allow smaller binaries with --gc-sections]),
[], [enable_function_sections=no])
AC_ARG_ENABLE([verbose-debug],
AS_HELP_STRING([--enable-verbose-debug, verbose debug logging]),
[], [enable_verbose_debug=no])
AC_ARG_ENABLE([clock-gettime],
AS_HELP_STRING(--disable-clock-gettime, do not use clock_gettime even if it is available),
[], [enable_clock_gettime=yes])
AC_PROG_LIBTOOL
dnl Uncomment "AC_DISABLE_SHARED" to make shared libraries not get
dnl built by default. You can also turn shared libs on and off from
dnl the command line with --enable-shared and --disable-shared.
dnl AC_DISABLE_SHARED
AC_SUBST(LIBTOOL_DEPS)
AM_CONDITIONAL([BUILD_SAMPLES], [test "$enable_samples" = "yes"])
AM_CONDITIONAL([BUILD_REGRESS], [test "$enable_libevent_regress" = "yes"])
dnl Checks for libraries.
AC_SEARCH_LIBS([inet_ntoa], [nsl])
AC_SEARCH_LIBS([socket], [socket])
AC_SEARCH_LIBS([inet_aton], [resolv])
if test "x$enable_clock_gettime" = "xyes"; then
AC_SEARCH_LIBS([clock_gettime], [rt])
AC_CHECK_FUNCS([clock_gettime])
fi
AC_SEARCH_LIBS([sendfile], [sendfile])
dnl - check if the macro _WIN32 is defined on this compiler.
dnl - (this is how we check for a windows compiler)
AC_MSG_CHECKING(for WIN32)
AC_TRY_COMPILE(,
[
#ifndef _WIN32
die horribly
#endif
],
bwin32=true; AC_MSG_RESULT(yes),
bwin32=false; AC_MSG_RESULT(no),
)
dnl - check if the macro __CYGWIN__ is defined on this compiler.
dnl - (this is how we check for a cygwin version of GCC)
AC_MSG_CHECKING(for CYGWIN)
AC_TRY_COMPILE(,
[
#ifndef __CYGWIN__
die horribly
#endif
],
cygwin=true; AC_MSG_RESULT(yes),
cygwin=false; AC_MSG_RESULT(no),
)
AC_CHECK_HEADERS([zlib.h])
if test "x$ac_cv_header_zlib_h" = "xyes"; then
dnl Determine if we have zlib for regression tests
dnl Don't put this one in LIBS
save_LIBS="$LIBS"
LIBS=""
ZLIB_LIBS=""
have_zlib=no
AC_SEARCH_LIBS([inflateEnd], [z],
[have_zlib=yes
ZLIB_LIBS="$LIBS"
AC_DEFINE(HAVE_LIBZ, 1, [Define if the system has zlib])])
LIBS="$save_LIBS"
AC_SUBST(ZLIB_LIBS)
fi
AM_CONDITIONAL(ZLIB_REGRESS, [test "$have_zlib" = "yes"])
dnl See if we have openssl. This doesn't go in LIBS either.
if test "$bwin32" = true; then
EV_LIB_WS32=-lws2_32
EV_LIB_GDI=-lgdi32
else
EV_LIB_WS32=
EV_LIB_GDI=
fi
AC_SUBST(EV_LIB_WS32)
AC_SUBST(EV_LIB_GDI)
AC_SUBST(OPENSSL_LIBADD)
AC_SYS_LARGEFILE
LIBEVENT_OPENSSL
dnl Checks for header files.
AC_CHECK_HEADERS([ \
arpa/inet.h \
fcntl.h \
ifaddrs.h \
mach/mach_time.h \
netdb.h \
netinet/in.h \
netinet/in6.h \
netinet/tcp.h \
poll.h \
port.h \
stdarg.h \
stddef.h \
sys/devpoll.h \
sys/epoll.h \
sys/event.h \
sys/eventfd.h \
sys/ioctl.h \
sys/mman.h \
sys/param.h \
sys/queue.h \
sys/resource.h \
sys/select.h \
sys/sendfile.h \
sys/socket.h \
sys/stat.h \
sys/time.h \
sys/timerfd.h \
sys/uio.h \
sys/wait.h \
errno.h \
])
AC_CHECK_HEADERS(sys/sysctl.h, [], [], [
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
])
if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
AC_EGREP_CPP(yes,
[
#include <sys/queue.h>
#ifdef TAILQ_FOREACH
yes
#endif
], [AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_TAILQFOREACH, 1,
[Define if TAILQ_FOREACH is defined in <sys/queue.h>])],
AC_MSG_RESULT(no)
)
fi
if test "x$ac_cv_header_sys_time_h" = "xyes"; then
AC_MSG_CHECKING(for timeradd in sys/time.h)
AC_EGREP_CPP(yes,
[
#include <sys/time.h>
#ifdef timeradd
yes
#endif
], [ AC_DEFINE(HAVE_TIMERADD, 1,
[Define if timeradd is defined in <sys/time.h>])
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
)
fi
if test "x$ac_cv_header_sys_time_h" = "xyes"; then
AC_MSG_CHECKING(for timercmp in sys/time.h)
AC_EGREP_CPP(yes,
[
#include <sys/time.h>
#ifdef timercmp
yes
#endif
], [ AC_DEFINE(HAVE_TIMERCMP, 1,
[Define if timercmp is defined in <sys/time.h>])
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
)
fi
if test "x$ac_cv_header_sys_time_h" = "xyes"; then
AC_MSG_CHECKING(for timerclear in sys/time.h)
AC_EGREP_CPP(yes,
[
#include <sys/time.h>
#ifdef timerclear
yes
#endif
], [ AC_DEFINE(HAVE_TIMERCLEAR, 1,
[Define if timerclear is defined in <sys/time.h>])
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
)
fi
if test "x$ac_cv_header_sys_time_h" = "xyes"; then
AC_MSG_CHECKING(for timerisset in sys/time.h)
AC_EGREP_CPP(yes,
[
#include <sys/time.h>
#ifdef timerisset
yes
#endif
], [ AC_DEFINE(HAVE_TIMERISSET, 1,
[Define if timerisset is defined in <sys/time.h>])
AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
)
fi
if test "x$ac_cv_header_sys_sysctl_h" = "xyes"; then
AC_CHECK_DECLS([CTL_KERN, KERN_RANDOM, RANDOM_UUID, KERN_ARND], [], [],
[[#include <sys/types.h>
#include <sys/sysctl.h>]]
)
fi
AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue)
AM_CONDITIONAL(BUILD_CYGWIN, test x$cygwin = xtrue)
AM_CONDITIONAL(BUILD_WITH_NO_UNDEFINED, test x$bwin32 = xtrue || test x$cygwin = xtrue)
if test x$bwin32 = xtrue; then
AC_SEARCH_LIBS([getservbyname],[ws2_32])
fi
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_HEADER_TIME
dnl Checks for library functions.
AC_CHECK_FUNCS([ \
accept4 \
arc4random \
arc4random_buf \
eventfd \
epoll_create1 \
fcntl \
getegid \
geteuid \
getifaddrs \
getnameinfo \
getprotobynumber \
gettimeofday \
inet_ntop \
inet_pton \
issetugid \
mach_absolute_time \
mmap \
nanosleep \
pipe \
pipe2 \
putenv \
sendfile \
setenv \
setrlimit \
sigaction \
signal \
splice \
strlcpy \
strsep \
strtok_r \
strtoll \
sysctl \
timerfd_create \
umask \
unsetenv \
usleep \
vasprintf \
getservbyname \
])
AM_CONDITIONAL(STRLCPY_IMPL, [test x"$ac_cv_func_strlcpy" = xno])
AC_CACHE_CHECK(
[for getaddrinfo],
[libevent_cv_getaddrinfo],
[AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
]],
[[
getaddrinfo;
]]
)],
[libevent_cv_getaddrinfo=yes],
[libevent_cv_getaddrinfo=no]
)]
)
if test "$libevent_cv_getaddrinfo" = "yes" ; then
AC_DEFINE([HAVE_GETADDRINFO], [1], [Do we have getaddrinfo()?])
else
# Check for gethostbyname_r in all its glorious incompatible versions.
# (This is cut-and-pasted from Tor, which based its logic on
# Python's configure.in.)
AH_TEMPLATE(HAVE_GETHOSTBYNAME_R,
[Define this if you have any gethostbyname_r()])
AC_CHECK_FUNC(gethostbyname_r, [
AC_MSG_CHECKING([how many arguments gethostbyname_r() wants])
OLD_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <netdb.h>
], [[
char *cp1, *cp2;
struct hostent *h1, *h2;
int i1, i2;
(void)gethostbyname_r(cp1,h1,cp2,i1,&h2,&i2);
]])],[
AC_DEFINE(HAVE_GETHOSTBYNAME_R)
AC_DEFINE(HAVE_GETHOSTBYNAME_R_6_ARG, 1,
[Define this if gethostbyname_r takes 6 arguments])
AC_MSG_RESULT(6)
], [
AC_TRY_COMPILE([
#include <netdb.h>
], [
char *cp1, *cp2;
struct hostent *h1;
int i1, i2;
(void)gethostbyname_r(cp1,h1,cp2,i1,&i2);
], [
AC_DEFINE(HAVE_GETHOSTBYNAME_R)
AC_DEFINE(HAVE_GETHOSTBYNAME_R_5_ARG, 1,
[Define this if gethostbyname_r takes 5 arguments])
AC_MSG_RESULT(5)
], [
AC_TRY_COMPILE([
#include <netdb.h>
], [
char *cp1;
struct hostent *h1;
struct hostent_data hd;
(void) gethostbyname_r(cp1,h1,&hd);
], [
AC_DEFINE(HAVE_GETHOSTBYNAME_R)
AC_DEFINE(HAVE_GETHOSTBYNAME_R_3_ARG, 1,
[Define this if gethostbyname_r takes 3 arguments])
AC_MSG_RESULT(3)
], [
AC_MSG_RESULT(0)
])
])
])
CFLAGS=$OLD_CFLAGS
])
fi
AC_MSG_CHECKING(for F_SETFD in fcntl.h)
AC_EGREP_CPP(yes,
[
#define _GNU_SOURCE
#include <fcntl.h>
#ifdef F_SETFD
yes
#endif
], [ AC_DEFINE(HAVE_SETFD, 1,
[Define if F_SETFD is defined in <fcntl.h>])
AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no))
needsignal=no
haveselect=no
if test x$bwin32 != xtrue; then
AC_CHECK_FUNCS(select, [haveselect=yes], )
if test "x$haveselect" = "xyes" ; then
needsignal=yes
fi
fi
AM_CONDITIONAL(SELECT_BACKEND, [test "x$haveselect" = "xyes"])
havepoll=no
AC_CHECK_FUNCS(poll, [havepoll=yes], )
if test "x$havepoll" = "xyes" ; then
needsignal=yes
fi
AM_CONDITIONAL(POLL_BACKEND, [test "x$havepoll" = "xyes"])
havedevpoll=no
if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
AC_DEFINE(HAVE_DEVPOLL, 1,
[Define if /dev/poll is available])
fi
AM_CONDITIONAL(DEVPOLL_BACKEND, [test "x$ac_cv_header_sys_devpoll_h" = "xyes"])
havekqueue=no
if test "x$ac_cv_header_sys_event_h" = "xyes"; then
AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
if test "x$havekqueue" = "xyes" ; then
AC_MSG_CHECKING(for working kqueue)
AC_TRY_RUN(
#include <sys/types.h>
#include <sys/time.h>
#include <sys/event.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int
main(int argc, char **argv)
{
int kq;
int n;
int fd[[2]];
struct kevent ev;
struct timespec ts;
char buf[[8000]];
if (pipe(fd) == -1)
exit(1);
if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
exit(1);
while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
;
if ((kq = kqueue()) == -1)
exit(1);
memset(&ev, 0, sizeof(ev));
ev.ident = fd[[1]];
ev.filter = EVFILT_WRITE;
ev.flags = EV_ADD | EV_ENABLE;
n = kevent(kq, &ev, 1, NULL, 0, NULL);
if (n == -1)
exit(1);
read(fd[[0]], buf, sizeof(buf));
ts.tv_sec = 0;
ts.tv_nsec = 0;
n = kevent(kq, NULL, 0, &ev, 1, &ts);
if (n == -1 || n == 0)
exit(1);
exit(0);
}, [AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
[Define if kqueue works correctly with pipes])
havekqueue=yes
], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
fi
fi
AM_CONDITIONAL(KQUEUE_BACKEND, [test "x$havekqueue" = "xyes"])
haveepollsyscall=no
haveepoll=no
AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], )
if test "x$haveepoll" = "xyes" ; then
AC_DEFINE(HAVE_EPOLL, 1,
[Define if your system supports the epoll system calls])
needsignal=yes
fi
if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
if test "x$haveepoll" = "xno" ; then
AC_MSG_CHECKING(for epoll system call)
AC_TRY_RUN(
#include <stdint.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/epoll.h>
#include <unistd.h>
int
epoll_create(int size)
{
return (syscall(__NR_epoll_create, size));
}
int
main(int argc, char **argv)
{
int epfd;
epfd = epoll_create(256);
exit (epfd == -1 ? 1 : 0);
}, [AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_EPOLL, 1,
[Define if your system supports the epoll system calls])
needsignal=yes
have_epoll=yes
AC_LIBOBJ(epoll_sub)
], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
fi
fi
AM_CONDITIONAL(EPOLL_BACKEND, [test "x$haveepoll" = "xyes"])
AC_MSG_CHECKING(waitpid support WNOWAIT)
AC_TRY_RUN(
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int
main(int argc, char** argv)
{
pid_t pid;
int status;
if ((pid = fork()) == 0) _exit(0);
_exit(waitpid(pid, &status, WNOWAIT) == -1);
}, [AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_WAITPID_WITH_WNOWAIT, 1,
[Define if waitpid() supports WNOWAIT])
], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
haveeventports=no
AC_CHECK_FUNCS(port_create, [haveeventports=yes], )
if test "x$haveeventports" = "xyes" ; then
AC_DEFINE(HAVE_EVENT_PORTS, 1,
[Define if your system supports event ports])
needsignal=yes
fi
AM_CONDITIONAL(EVPORT_BACKEND, [test "x$haveeventports" = "xyes"])
if test "x$bwin32" = "xtrue"; then
needsignal=yes
fi
AM_CONDITIONAL(SIGNAL_SUPPORT, [test "x$needsignal" = "xyes"])
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_t, uintptr_t], , ,
[#ifdef HAVE_STDINT_H
#include <stdint.h>
#elif defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif])
AC_CHECK_TYPES([fd_mask], , ,
[#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif])
AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(void *)
AC_CHECK_SIZEOF(off_t)
AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t, struct addrinfo, struct sockaddr_storage], , ,
[#define _GNU_SOURCE
#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef _WIN32
#define WIN32_WINNT 0x400
#define _WIN32_WINNT 0x400
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER) && (_MSC_VER < 1300)
#include <winsock.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#endif
])
AC_CHECK_MEMBERS([struct in6_addr.s6_addr32, struct in6_addr.s6_addr16, struct sockaddr_in.sin_len, struct sockaddr_in6.sin6_len, struct sockaddr_storage.ss_family, struct sockaddr_storage.__ss_family], , ,
[#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef _WIN32
#define WIN32_WINNT 0x400
#define _WIN32_WINNT 0x400
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER) && (_MSC_VER < 1300)
#include <winsock.h>
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#endif
])
AC_CHECK_TYPES([struct so_linger],
[#define HAVE_SO_LINGER], ,
[
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
])
AC_MSG_CHECKING([for socklen_t])
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>],
[socklen_t x;],
AC_MSG_RESULT([yes]),
[AC_MSG_RESULT([no])
AC_DEFINE(socklen_t, unsigned int,
[Define to unsigned int if you dont have it])]
)
AC_MSG_CHECKING([whether our compiler supports __func__])
AC_TRY_COMPILE([],
[ const char *cp = __func__; ],
AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no])
AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
AC_TRY_COMPILE([],
[ const char *cp = __FUNCTION__; ],
AC_MSG_RESULT([yes])
AC_DEFINE(__func__, __FUNCTION__,
[Define to appropriate substitue if compiler doesnt have __func__]),
AC_MSG_RESULT([no])
AC_DEFINE(__func__, __FILE__,
[Define to appropriate substitue if compiler doesnt have __func__])))
# check if we can compile with pthreads
have_pthreads=no
if test x$bwin32 != xtrue && test "$enable_thread_support" != "no"; then
ACX_PTHREAD([
AC_DEFINE(HAVE_PTHREADS, 1,
[Define if we have pthreads on this system])
have_pthreads=yes])
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
AC_CHECK_SIZEOF(pthread_t, ,
[AC_INCLUDES_DEFAULT()
#include <pthread.h> ]
)
fi
AM_CONDITIONAL(THREADS, [test "$enable_thread_support" != "no"])
AM_CONDITIONAL(PTHREADS, [test "$have_pthreads" != "no" && test "$enable_thread_support" != "no"])
# check if we should compile locking into the library
if test x$enable_thread_support = xno; then
AC_DEFINE(DISABLE_THREAD_SUPPORT, 1,
[Define if libevent should not be compiled with thread support])
fi
# check if we should hard-code the mm functions.
if test x$enable_malloc_replacement = xno; then
AC_DEFINE(DISABLE_MM_REPLACEMENT, 1,
[Define if libevent should not allow replacing the mm functions])
fi
# check if we should hard-code debugging out
if test x$enable_debug_mode = xno; then
AC_DEFINE(DISABLE_DEBUG_MODE, 1,
[Define if libevent should build without support for a debug mode])
fi
# check if we should enable verbose debugging
if test x$enable_verbose_debug = xyes; then
CFLAGS="$CFLAGS -DUSE_DEBUG"
fi
# check if we have and should use openssl
AM_CONDITIONAL(OPENSSL, [test "$enable_openssl" != "no" && test "$have_openssl" = "yes"])
if test "x$enable_openssl" = "xyes"; then
AC_SEARCH_LIBS([ERR_remove_thread_state], [crypto eay32],
[AC_DEFINE(HAVE_ERR_REMOVE_THREAD_STATE, 1, [Define to 1 if you have ERR_remove_thread_stat().])])
fi
# Add some more warnings which we use in development but not in the
# released versions. (Some relevant gcc versions can't handle these.)
if test x$enable_gcc_warnings != xno && test "$GCC" = "yes"; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__GNUC__) || (__GNUC__ < 4)
#error
#endif])], have_gcc4=yes, have_gcc4=no)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
#error
#endif])], have_gcc42=yes, have_gcc42=no)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
#error
#endif])], have_gcc45=yes, have_gcc45=no)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__clang__)
#error
#endif])], have_clang=yes, have_clang=no)
CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch"
if test x$enable_gcc_warnings = xyes; then
CFLAGS="$CFLAGS -Werror"
fi
CFLAGS="$CFLAGS -Wno-unused-parameter -Wstrict-aliasing"
if test x$have_gcc4 = xyes ; then
# These warnings break gcc 3.3.5 and work on gcc 4.0.2
CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement"
#CFLAGS="$CFLAGS -Wold-style-definition"
fi
if test x$have_gcc42 = xyes ; then
# These warnings break gcc 4.0.2 and work on gcc 4.2
CFLAGS="$CFLAGS -Waddress"
fi
if test x$have_gcc42 = xyes && test x$have_clang = xno; then
# These warnings break gcc 4.0.2 and clang, but work on gcc 4.2
CFLAGS="$CFLAGS -Wnormalized=id -Woverride-init"
fi
if test x$have_gcc45 = xyes ; then
# These warnings work on gcc 4.5
CFLAGS="$CFLAGS -Wlogical-op"
fi
if test x$have_clang = xyes; then
# Disable the unused-function warnings, because these trigger
# for minheap-internal.h related code.
CFLAGS="$CFLAGS -Wno-unused-function"
# clang on macosx emits warnigns for each directory specified which
# isn't "used" generating a lot of build noise (typically 3 warnings
# per file
case "$host_os" in
darwin*)
CFLAGS="$CFLAGS -Qunused-arguments"
;;
esac
fi
##This will break the world on some 64-bit architectures
# CFLAGS="$CFLAGS -Winline"
fi
LIBEVENT_GC_SECTIONS=
if test "$GCC" = yes && test "$enable_function_sections" = yes ; then
AC_CACHE_CHECK(
[if linker supports omitting unused code and data],
[libevent_cv_gc_sections_runs],
[
dnl NetBSD will link but likely not run with --gc-sections
dnl http://bugs.ntp.org/1844
dnl http://gnats.netbsd.org/40401
dnl --gc-sections causes attempt to load as linux elf, with
dnl wrong syscalls in place. Test a little gauntlet of
dnl simple stdio read code checking for errors, expecting
dnl enough syscall differences that the NetBSD code will
dnl fail even with Linux emulation working as designed.
dnl A shorter test could be refined by someone with access
dnl to a NetBSD host with Linux emulation working.
origCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wl,--gc-sections"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdlib.h>
#include <stdio.h>
]],
[[
FILE * fpC;
char buf[32];
size_t cch;
int read_success_once;
fpC = fopen("conftest.c", "r");
if (NULL == fpC)
exit(1);
do {
cch = fread(buf, sizeof(buf), 1, fpC);
read_success_once |= (0 != cch);
} while (0 != cch);
if (!read_success_once)
exit(2);
if (!feof(fpC))
exit(3);
if (0 != fclose(fpC))
exit(4);
exit(EXIT_SUCCESS);
]]
)],
[
dnl We have to do this invocation manually so that we can
dnl get the output of conftest.err to make sure it doesn't
dnl mention gc-sections.
if test "X$cross_compiling" = "Xyes" || grep gc-sections conftest.err ; then
libevent_cv_gc_sections_runs=no
else
libevent_cv_gc_sections_runs=no
./conftest >/dev/null 2>&1 && libevent_cv_gc_sections_runs=yes
fi
],
[libevent_cv_gc_sections_runs=no]
)
CFLAGS="$origCFLAGS"
AS_UNSET([origCFLAGS])
]
)
case "$libevent_cv_gc_sections_runs" in
yes)
CFLAGS="-ffunction-sections -fdata-sections $CFLAGS"
LIBEVENT_GC_SECTIONS="-Wl,--gc-sections"
;;
esac
fi
AC_SUBST([LIBEVENT_GC_SECTIONS])
AM_CONDITIONAL([INSTALL_LIBEVENT], [test "$enable_libevent_install" = "yes"])
AC_CONFIG_FILES( [libevent.pc libevent_openssl.pc libevent_pthreads.pc libevent_core.pc libevent_extra.pc] )
AC_OUTPUT(Makefile)

View File

@ -0,0 +1,70 @@
/*
* 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_ */

791
contrib/libevent/depcomp Executable file
View File

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

311
contrib/libevent/devpoll.c Normal file
View File

@ -0,0 +1,311 @@
/*
* Copyright 2000-2009 Niels Provos <provos@citi.umich.edu>
* 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 EVENT__HAVE_DEVPOLL
#include <sys/types.h>
#include <sys/resource.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <sys/devpoll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "event2/event.h"
#include "event2/event_struct.h"
#include "event2/thread.h"
#include "event-internal.h"
#include "evsignal-internal.h"
#include "log-internal.h"
#include "evmap-internal.h"
#include "evthread-internal.h"
struct devpollop {
struct pollfd *events;
int nevents;
int dpfd;
struct pollfd *changes;
int nchanges;
};
static void *devpoll_init(struct event_base *);
static int devpoll_add(struct event_base *, int fd, short old, short events, void *);
static int devpoll_del(struct event_base *, int fd, short old, short events, void *);
static int devpoll_dispatch(struct event_base *, struct timeval *);
static void devpoll_dealloc(struct event_base *);
const struct eventop devpollops = {
"devpoll",
devpoll_init,
devpoll_add,
devpoll_del,
devpoll_dispatch,
devpoll_dealloc,
1, /* need reinit */
EV_FEATURE_FDS|EV_FEATURE_O1,
0
};
#define NEVENT 32000
static int
devpoll_commit(struct devpollop *devpollop)
{
/*
* Due to a bug in Solaris, we have to use pwrite with an offset of 0.
* Write is limited to 2GB of data, until it will fail.
*/
if (pwrite(devpollop->dpfd, devpollop->changes,
sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
return (-1);
devpollop->nchanges = 0;
return (0);
}
static int
devpoll_queue(struct devpollop *devpollop, int fd, int events) {
struct pollfd *pfd;
if (devpollop->nchanges >= devpollop->nevents) {
/*
* Change buffer is full, must commit it to /dev/poll before
* adding more
*/
if (devpoll_commit(devpollop) != 0)
return (-1);
}
pfd = &devpollop->changes[devpollop->nchanges++];
pfd->fd = fd;
pfd->events = events;
pfd->revents = 0;
return (0);
}
static void *
devpoll_init(struct event_base *base)
{
int dpfd, nfiles = NEVENT;
struct rlimit rl;
struct devpollop *devpollop;
if (!(devpollop = mm_calloc(1, sizeof(struct devpollop))))
return (NULL);
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
rl.rlim_cur != RLIM_INFINITY)
nfiles = rl.rlim_cur;
/* Initialize the kernel queue */
if ((dpfd = evutil_open_closeonexec_("/dev/poll", O_RDWR, 0)) == -1) {
event_warn("open: /dev/poll");
mm_free(devpollop);
return (NULL);
}
devpollop->dpfd = dpfd;
/* Initialize fields */
/* FIXME: allocating 'nfiles' worth of space here can be
* expensive and unnecessary. See how epoll.c does it instead. */
devpollop->events = mm_calloc(nfiles, sizeof(struct pollfd));
if (devpollop->events == NULL) {
mm_free(devpollop);
close(dpfd);
return (NULL);
}
devpollop->nevents = nfiles;
devpollop->changes = mm_calloc(nfiles, sizeof(struct pollfd));
if (devpollop->changes == NULL) {
mm_free(devpollop->events);
mm_free(devpollop);
close(dpfd);
return (NULL);
}
evsig_init_(base);
return (devpollop);
}
static int
devpoll_dispatch(struct event_base *base, struct timeval *tv)
{
struct devpollop *devpollop = base->evbase;
struct pollfd *events = devpollop->events;
struct dvpoll dvp;
int i, res, timeout = -1;
if (devpollop->nchanges)
devpoll_commit(devpollop);
if (tv != NULL)
timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
dvp.dp_fds = devpollop->events;
dvp.dp_nfds = devpollop->nevents;
dvp.dp_timeout = timeout;
EVBASE_RELEASE_LOCK(base, th_base_lock);
res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (res == -1) {
if (errno != EINTR) {
event_warn("ioctl: DP_POLL");
return (-1);
}
return (0);
}
event_debug(("%s: devpoll_wait reports %d", __func__, res));
for (i = 0; i < res; i++) {
int which = 0;
int what = events[i].revents;
if (what & POLLHUP)
what |= POLLIN | POLLOUT;
else if (what & POLLERR)
what |= POLLIN | POLLOUT;
if (what & POLLIN)
which |= EV_READ;
if (what & POLLOUT)
which |= EV_WRITE;
if (!which)
continue;
/* XXX(niels): not sure if this works for devpoll */
evmap_io_active_(base, events[i].fd, which);
}
return (0);
}
static int
devpoll_add(struct event_base *base, int fd, short old, short events, void *p)
{
struct devpollop *devpollop = base->evbase;
int res;
(void)p;
/*
* It's not necessary to OR the existing read/write events that we
* are currently interested in with the new event we are adding.
* The /dev/poll driver ORs any new events with the existing events
* that it has cached for the fd.
*/
res = 0;
if (events & EV_READ)
res |= POLLIN;
if (events & EV_WRITE)
res |= POLLOUT;
if (devpoll_queue(devpollop, fd, res) != 0)
return (-1);
return (0);
}
static int
devpoll_del(struct event_base *base, int fd, short old, short events, void *p)
{
struct devpollop *devpollop = base->evbase;
int res;
(void)p;
res = 0;
if (events & EV_READ)
res |= POLLIN;
if (events & EV_WRITE)
res |= POLLOUT;
/*
* The only way to remove an fd from the /dev/poll monitored set is
* to use POLLREMOVE by itself. This removes ALL events for the fd
* provided so if we care about two events and are only removing one
* we must re-add the other event after POLLREMOVE.
*/
if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
return (-1);
if ((res & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
/*
* We're not deleting all events, so we must resubmit the
* event that we are still interested in if one exists.
*/
if ((res & POLLIN) && (old & EV_WRITE)) {
/* Deleting read, still care about write */
devpoll_queue(devpollop, fd, POLLOUT);
} else if ((res & POLLOUT) && (old & EV_READ)) {
/* Deleting write, still care about read */
devpoll_queue(devpollop, fd, POLLIN);
}
}
return (0);
}
static void
devpoll_dealloc(struct event_base *base)
{
struct devpollop *devpollop = base->evbase;
evsig_dealloc_(base);
if (devpollop->events)
mm_free(devpollop->events);
if (devpollop->changes)
mm_free(devpollop->changes);
if (devpollop->dpfd >= 0)
close(devpollop->dpfd);
memset(devpollop, 0, sizeof(struct devpollop));
mm_free(devpollop);
}
#endif /* EVENT__HAVE_DEVPOLL */

540
contrib/libevent/epoll.c Normal file
View File

@ -0,0 +1,540 @@
/*
* Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
* Copyright 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"
#ifdef EVENT__HAVE_EPOLL
#include <stdint.h>
#include <sys/types.h>
#include <sys/resource.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <sys/epoll.h>
#include <signal.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#ifdef EVENT__HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef EVENT__HAVE_SYS_TIMERFD_H
#include <sys/timerfd.h>
#endif
#include "event-internal.h"
#include "evsignal-internal.h"
#include "event2/thread.h"
#include "evthread-internal.h"
#include "log-internal.h"
#include "evmap-internal.h"
#include "changelist-internal.h"
#include "time-internal.h"
/* Since Linux 2.6.17, epoll is able to report about peer half-closed connection
using special EPOLLRDHUP flag on a read event.
*/
#if !defined(EPOLLRDHUP)
#define EPOLLRDHUP 0
#define EARLY_CLOSE_IF_HAVE_RDHUP 0
#else
#define EARLY_CLOSE_IF_HAVE_RDHUP EV_FEATURE_EARLY_CLOSE
#endif
#include "epolltable-internal.h"
#if defined(EVENT__HAVE_SYS_TIMERFD_H) && \
defined(EVENT__HAVE_TIMERFD_CREATE) && \
defined(HAVE_POSIX_MONOTONIC) && defined(TFD_NONBLOCK) && \
defined(TFD_CLOEXEC)
/* Note that we only use timerfd if TFD_NONBLOCK and TFD_CLOEXEC are available
and working. This means that we can't support it on 2.6.25 (where timerfd
was introduced) or 2.6.26, since 2.6.27 introduced those flags.
*/
#define USING_TIMERFD
#endif
struct epollop {
struct epoll_event *events;
int nevents;
int epfd;
#ifdef USING_TIMERFD
int timerfd;
#endif
};
static void *epoll_init(struct event_base *);
static int epoll_dispatch(struct event_base *, struct timeval *);
static void epoll_dealloc(struct event_base *);
static const struct eventop epollops_changelist = {
"epoll (with changelist)",
epoll_init,
event_changelist_add_,
event_changelist_del_,
epoll_dispatch,
epoll_dealloc,
1, /* need reinit */
EV_FEATURE_ET|EV_FEATURE_O1| EARLY_CLOSE_IF_HAVE_RDHUP,
EVENT_CHANGELIST_FDINFO_SIZE
};
static int epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
short old, short events, void *p);
static int epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
short old, short events, void *p);
const struct eventop epollops = {
"epoll",
epoll_init,
epoll_nochangelist_add,
epoll_nochangelist_del,
epoll_dispatch,
epoll_dealloc,
1, /* need reinit */
EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_EARLY_CLOSE,
0
};
#define INITIAL_NEVENT 32
#define MAX_NEVENT 4096
/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
* values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be
* as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
* largest number of msec we can support here is 2147482. Let's
* round that down by 47 seconds.
*/
#define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
static void *
epoll_init(struct event_base *base)
{
int epfd = -1;
struct epollop *epollop;
#ifdef EVENT__HAVE_EPOLL_CREATE1
/* First, try the shiny new epoll_create1 interface, if we have it. */
epfd = epoll_create1(EPOLL_CLOEXEC);
#endif
if (epfd == -1) {
/* Initialize the kernel queue using the old interface. (The
size field is ignored since 2.6.8.) */
if ((epfd = epoll_create(32000)) == -1) {
if (errno != ENOSYS)
event_warn("epoll_create");
return (NULL);
}
evutil_make_socket_closeonexec(epfd);
}
if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) {
close(epfd);
return (NULL);
}
epollop->epfd = epfd;
/* Initialize fields */
epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
if (epollop->events == NULL) {
mm_free(epollop);
close(epfd);
return (NULL);
}
epollop->nevents = INITIAL_NEVENT;
if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 ||
((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
evutil_getenv_("EVENT_EPOLL_USE_CHANGELIST") != NULL)) {
base->evsel = &epollops_changelist;
}
#ifdef USING_TIMERFD
/*
The epoll interface ordinarily gives us one-millisecond precision,
so on Linux it makes perfect sense to use the CLOCK_MONOTONIC_COARSE
timer. But when the user has set the new PRECISE_TIMER flag for an
event_base, we can try to use timerfd to give them finer granularity.
*/
if ((base->flags & EVENT_BASE_FLAG_PRECISE_TIMER) &&
base->monotonic_timer.monotonic_clock == CLOCK_MONOTONIC) {
int fd;
fd = epollop->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
if (epollop->timerfd >= 0) {
struct epoll_event epev;
memset(&epev, 0, sizeof(epev));
epev.data.fd = epollop->timerfd;
epev.events = EPOLLIN;
if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, fd, &epev) < 0) {
event_warn("epoll_ctl(timerfd)");
close(fd);
epollop->timerfd = -1;
}
} else {
if (errno != EINVAL && errno != ENOSYS) {
/* These errors probably mean that we were
* compiled with timerfd/TFD_* support, but
* we're running on a kernel that lacks those.
*/
event_warn("timerfd_create");
}
epollop->timerfd = -1;
}
} else {
epollop->timerfd = -1;
}
#endif
evsig_init_(base);
return (epollop);
}
static const char *
change_to_string(int change)
{
change &= (EV_CHANGE_ADD|EV_CHANGE_DEL);
if (change == EV_CHANGE_ADD) {
return "add";
} else if (change == EV_CHANGE_DEL) {
return "del";
} else if (change == 0) {
return "none";
} else {
return "???";
}
}
static const char *
epoll_op_to_string(int op)
{
return op == EPOLL_CTL_ADD?"ADD":
op == EPOLL_CTL_DEL?"DEL":
op == EPOLL_CTL_MOD?"MOD":
"???";
}
#define PRINT_CHANGES(op, events, ch, status) \
"Epoll %s(%d) on fd %d " status ". " \
"Old events were %d; " \
"read change was %d (%s); " \
"write change was %d (%s); " \
"close change was %d (%s)", \
epoll_op_to_string(op), \
events, \
ch->fd, \
ch->old_events, \
ch->read_change, \
change_to_string(ch->read_change), \
ch->write_change, \
change_to_string(ch->write_change), \
ch->close_change, \
change_to_string(ch->close_change)
static int
epoll_apply_one_change(struct event_base *base,
struct epollop *epollop,
const struct event_change *ch)
{
struct epoll_event epev;
int op, events = 0;
int idx;
idx = EPOLL_OP_TABLE_INDEX(ch);
op = epoll_op_table[idx].op;
events = epoll_op_table[idx].events;
if (!events) {
EVUTIL_ASSERT(op == 0);
return 0;
}
if ((ch->read_change|ch->write_change) & EV_CHANGE_ET)
events |= EPOLLET;
memset(&epev, 0, sizeof(epev));
epev.data.fd = ch->fd;
epev.events = events;
if (epoll_ctl(epollop->epfd, op, ch->fd, &epev) == 0) {
event_debug((PRINT_CHANGES(op, epev.events, ch, "okay")));
return 0;
}
switch (op) {
case EPOLL_CTL_MOD:
if (errno == ENOENT) {
/* If a MOD operation fails with ENOENT, the
* fd was probably closed and re-opened. We
* should retry the operation as an ADD.
*/
if (epoll_ctl(epollop->epfd, EPOLL_CTL_ADD, ch->fd, &epev) == -1) {
event_warn("Epoll MOD(%d) on %d retried as ADD; that failed too",
(int)epev.events, ch->fd);
return -1;
} else {
event_debug(("Epoll MOD(%d) on %d retried as ADD; succeeded.",
(int)epev.events,
ch->fd));
return 0;
}
}
break;
case EPOLL_CTL_ADD:
if (errno == EEXIST) {
/* If an ADD operation fails with EEXIST,
* either the operation was redundant (as with a
* precautionary add), or we ran into a fun
* kernel bug where using dup*() to duplicate the
* same file into the same fd gives you the same epitem
* rather than a fresh one. For the second case,
* we must retry with MOD. */
if (epoll_ctl(epollop->epfd, EPOLL_CTL_MOD, ch->fd, &epev) == -1) {
event_warn("Epoll ADD(%d) on %d retried as MOD; that failed too",
(int)epev.events, ch->fd);
return -1;
} else {
event_debug(("Epoll ADD(%d) on %d retried as MOD; succeeded.",
(int)epev.events,
ch->fd));
return 0;
}
}
break;
case EPOLL_CTL_DEL:
if (errno == ENOENT || errno == EBADF || errno == EPERM) {
/* If a delete fails with one of these errors,
* that's fine too: we closed the fd before we
* got around to calling epoll_dispatch. */
event_debug(("Epoll DEL(%d) on fd %d gave %s: DEL was unnecessary.",
(int)epev.events,
ch->fd,
strerror(errno)));
return 0;
}
break;
default:
break;
}
event_warn(PRINT_CHANGES(op, epev.events, ch, "failed"));
return -1;
}
static int
epoll_apply_changes(struct event_base *base)
{
struct event_changelist *changelist = &base->changelist;
struct epollop *epollop = base->evbase;
struct event_change *ch;
int r = 0;
int i;
for (i = 0; i < changelist->n_changes; ++i) {
ch = &changelist->changes[i];
if (epoll_apply_one_change(base, epollop, ch) < 0)
r = -1;
}
return (r);
}
static int
epoll_nochangelist_add(struct event_base *base, evutil_socket_t fd,
short old, short events, void *p)
{
struct event_change ch;
ch.fd = fd;
ch.old_events = old;
ch.read_change = ch.write_change = ch.close_change = 0;
if (events & EV_WRITE)
ch.write_change = EV_CHANGE_ADD |
(events & EV_ET);
if (events & EV_READ)
ch.read_change = EV_CHANGE_ADD |
(events & EV_ET);
if (events & EV_CLOSED)
ch.close_change = EV_CHANGE_ADD |
(events & EV_ET);
return epoll_apply_one_change(base, base->evbase, &ch);
}
static int
epoll_nochangelist_del(struct event_base *base, evutil_socket_t fd,
short old, short events, void *p)
{
struct event_change ch;
ch.fd = fd;
ch.old_events = old;
ch.read_change = ch.write_change = ch.close_change = 0;
if (events & EV_WRITE)
ch.write_change = EV_CHANGE_DEL;
if (events & EV_READ)
ch.read_change = EV_CHANGE_DEL;
if (events & EV_CLOSED)
ch.close_change = EV_CHANGE_DEL;
return epoll_apply_one_change(base, base->evbase, &ch);
}
static int
epoll_dispatch(struct event_base *base, struct timeval *tv)
{
struct epollop *epollop = base->evbase;
struct epoll_event *events = epollop->events;
int i, res;
long timeout = -1;
#ifdef USING_TIMERFD
if (epollop->timerfd >= 0) {
struct itimerspec is;
is.it_interval.tv_sec = 0;
is.it_interval.tv_nsec = 0;
if (tv == NULL) {
/* No timeout; disarm the timer. */
is.it_value.tv_sec = 0;
is.it_value.tv_nsec = 0;
} else {
if (tv->tv_sec == 0 && tv->tv_usec == 0) {
/* we need to exit immediately; timerfd can't
* do that. */
timeout = 0;
}
is.it_value.tv_sec = tv->tv_sec;
is.it_value.tv_nsec = tv->tv_usec * 1000;
}
/* TODO: we could avoid unnecessary syscalls here by only
calling timerfd_settime when the top timeout changes, or
when we're called with a different timeval.
*/
if (timerfd_settime(epollop->timerfd, 0, &is, NULL) < 0) {
event_warn("timerfd_settime");
}
} else
#endif
if (tv != NULL) {
timeout = evutil_tv_to_msec_(tv);
if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
/* Linux kernels can wait forever if the timeout is
* too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
timeout = MAX_EPOLL_TIMEOUT_MSEC;
}
}
epoll_apply_changes(base);
event_changelist_remove_all_(&base->changelist, base);
EVBASE_RELEASE_LOCK(base, th_base_lock);
res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (res == -1) {
if (errno != EINTR) {
event_warn("epoll_wait");
return (-1);
}
return (0);
}
event_debug(("%s: epoll_wait reports %d", __func__, res));
EVUTIL_ASSERT(res <= epollop->nevents);
for (i = 0; i < res; i++) {
int what = events[i].events;
short ev = 0;
#ifdef USING_TIMERFD
if (events[i].data.fd == epollop->timerfd)
continue;
#endif
if (what & (EPOLLHUP|EPOLLERR)) {
ev = EV_READ | EV_WRITE;
} else {
if (what & EPOLLIN)
ev |= EV_READ;
if (what & EPOLLOUT)
ev |= EV_WRITE;
if (what & EPOLLRDHUP)
ev |= EV_CLOSED;
}
if (!ev)
continue;
evmap_io_active_(base, events[i].data.fd, ev | EV_ET);
}
if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
/* We used all of the event space this time. We should
be ready for more events next time. */
int new_nevents = epollop->nevents * 2;
struct epoll_event *new_events;
new_events = mm_realloc(epollop->events,
new_nevents * sizeof(struct epoll_event));
if (new_events) {
epollop->events = new_events;
epollop->nevents = new_nevents;
}
}
return (0);
}
static void
epoll_dealloc(struct event_base *base)
{
struct epollop *epollop = base->evbase;
evsig_dealloc_(base);
if (epollop->events)
mm_free(epollop->events);
if (epollop->epfd >= 0)
close(epollop->epfd);
#ifdef USING_TIMERFD
if (epollop->timerfd >= 0)
close(epollop->timerfd);
#endif
memset(epollop, 0, sizeof(struct epollop));
mm_free(epollop);
}
#endif /* EVENT__HAVE_EPOLL */

View File

@ -0,0 +1,66 @@
/*
* Copyright 2003-2009 Niels Provos <provos@citi.umich.edu>
* 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 "evconfig-private.h"
#include <stdint.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <errno.h>
int
epoll_create(int size)
{
#if !defined(__NR_epoll_create) && defined(__NR_epoll_create1)
if (size <= 0) {
errno = EINVAL;
return -1;
}
return (syscall(__NR_epoll_create1, 0));
#else
return (syscall(__NR_epoll_create, size));
#endif
}
int
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
return (syscall(__NR_epoll_ctl, epfd, op, fd, event));
}
int
epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
{
#if !defined(__NR_epoll_wait) && defined(__NR_epoll_pwait)
return (syscall(__NR_epoll_pwait, epfd, events, maxevents, timeout, NULL, 0));
#else
return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout));
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,351 @@
/*
* 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_ */

View File

@ -0,0 +1,49 @@
/* evconfig-private.h. Generated from evconfig-private.h.in by configure. */
/* evconfig-private.h template - see "Configuration Header Templates" */
/* in AC manual. Kevin Bowling <kevin.bowling@kev009.com */
#ifndef EVCONFIG_PRIVATE_H_INCLUDED_
#define EVCONFIG_PRIVATE_H_INCLUDED_
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to 1 if on MINIX. */
#ifndef _MINIX
/* #undef _MINIX */
#endif
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#ifndef _POSIX_1_SOURCE
/* #undef _POSIX_1_SOURCE */
#endif
/* Define to 1 if you need to in order for `stat' and other things to work. */
#ifndef _POSIX_SOURCE
/* #undef _POSIX_SOURCE */
#endif
#endif

View File

@ -0,0 +1,48 @@
/* evconfig-private.h template - see "Configuration Header Templates" */
/* in AC manual. Kevin Bowling <kevin.bowling@kev009.com */
#ifndef EVCONFIG_PRIVATE_H_INCLUDED_
#define EVCONFIG_PRIVATE_H_INCLUDED_
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to 1 if on MINIX. */
#ifndef _MINIX
#undef _MINIX
#endif
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#ifndef _POSIX_1_SOURCE
#undef _POSIX_1_SOURCE
#endif
/* Define to 1 if you need to in order for `stat' and other things to work. */
#ifndef _POSIX_SOURCE
#undef _POSIX_SOURCE
#endif
#endif

4767
contrib/libevent/evdns.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,479 @@
/*
* 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_ */

3940
contrib/libevent/event.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,294 @@
/*
* 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
}

1728
contrib/libevent/event_rpcgen.py Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,605 @@
/*
* 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;
}

View File

@ -0,0 +1,117 @@
/*
* 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_ */

1055
contrib/libevent/evmap.c Normal file

File diff suppressed because it is too large Load Diff

451
contrib/libevent/evport.c Normal file
View File

@ -0,0 +1,451 @@
/*
* Submitted by David Pacheco (dp.spambait@gmail.com)
*
* Copyright 2006-2007 Niels Provos
* 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 SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2007 Sun Microsystems. All rights reserved.
* Use is subject to license terms.
*/
/*
* evport.c: event backend using Solaris 10 event ports. See port_create(3C).
* This implementation is loosely modeled after the one used for select(2) (in
* select.c).
*
* The outstanding events are tracked in a data structure called evport_data.
* Each entry in the ed_fds array corresponds to a file descriptor, and contains
* pointers to the read and write events that correspond to that fd. (That is,
* when the file is readable, the "read" event should handle it, etc.)
*
* evport_add and evport_del update this data structure. evport_dispatch uses it
* to determine where to callback when an event occurs (which it gets from
* port_getn).
*
* Helper functions are used: grow() grows the file descriptor array as
* necessary when large fd's come in. reassociate() takes care of maintaining
* the proper file-descriptor/event-port associations.
*
* As in the select(2) implementation, signals are handled by evsignal.
*/
#include "event2/event-config.h"
#include "evconfig-private.h"
#ifdef EVENT__HAVE_EVENT_PORTS
#include <sys/time.h>
#include <sys/queue.h>
#include <errno.h>
#include <poll.h>
#include <port.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "event2/thread.h"
#include "evthread-internal.h"
#include "event-internal.h"
#include "log-internal.h"
#include "evsignal-internal.h"
#include "evmap-internal.h"
#define INITIAL_EVENTS_PER_GETN 8
#define MAX_EVENTS_PER_GETN 4096
/*
* Per-file-descriptor information about what events we're subscribed to. These
* fields are NULL if no event is subscribed to either of them.
*/
struct fd_info {
/* combinations of EV_READ and EV_WRITE */
short fdi_what;
/* Index of this fd within ed_pending, plus 1. Zero if this fd is
* not in ed_pending. (The +1 is a hack so that memset(0) will set
* it to a nil index. */
int pending_idx_plus_1;
};
#define FDI_HAS_READ(fdi) ((fdi)->fdi_what & EV_READ)
#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_what & EV_WRITE)
#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
(FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
struct evport_data {
int ed_port; /* event port for system events */
/* How many elements of ed_pending should we look at? */
int ed_npending;
/* How many elements are allocated in ed_pending and pevtlist? */
int ed_maxevents;
/* fdi's that we need to reassoc */
int *ed_pending;
/* storage space for incoming events. */
port_event_t *ed_pevtlist;
};
static void* evport_init(struct event_base *);
static int evport_add(struct event_base *, int fd, short old, short events, void *);
static int evport_del(struct event_base *, int fd, short old, short events, void *);
static int evport_dispatch(struct event_base *, struct timeval *);
static void evport_dealloc(struct event_base *);
static int grow(struct evport_data *, int min_events);
const struct eventop evportops = {
"evport",
evport_init,
evport_add,
evport_del,
evport_dispatch,
evport_dealloc,
1, /* need reinit */
0, /* features */
sizeof(struct fd_info), /* fdinfo length */
};
/*
* Initialize the event port implementation.
*/
static void*
evport_init(struct event_base *base)
{
struct evport_data *evpd;
if (!(evpd = mm_calloc(1, sizeof(struct evport_data))))
return (NULL);
if ((evpd->ed_port = port_create()) == -1) {
mm_free(evpd);
return (NULL);
}
if (grow(evpd, INITIAL_EVENTS_PER_GETN) < 0) {
close(evpd->ed_port);
mm_free(evpd);
return NULL;
}
evpd->ed_npending = 0;
evsig_init_(base);
return (evpd);
}
static int
grow(struct evport_data *data, int min_events)
{
int newsize;
int *new_pending;
port_event_t *new_pevtlist;
if (data->ed_maxevents) {
newsize = data->ed_maxevents;
do {
newsize *= 2;
} while (newsize < min_events);
} else {
newsize = min_events;
}
new_pending = mm_realloc(data->ed_pending, sizeof(int)*newsize);
if (new_pending == NULL)
return -1;
data->ed_pending = new_pending;
new_pevtlist = mm_realloc(data->ed_pevtlist, sizeof(port_event_t)*newsize);
if (new_pevtlist == NULL)
return -1;
data->ed_pevtlist = new_pevtlist;
data->ed_maxevents = newsize;
return 0;
}
#ifdef CHECK_INVARIANTS
/*
* Checks some basic properties about the evport_data structure. Because it
* checks all file descriptors, this function can be expensive when the maximum
* file descriptor ever used is rather large.
*/
static void
check_evportop(struct evport_data *evpd)
{
EVUTIL_ASSERT(evpd);
EVUTIL_ASSERT(evpd->ed_port > 0);
}
/*
* Verifies very basic integrity of a given port_event.
*/
static void
check_event(port_event_t* pevt)
{
/*
* We've only registered for PORT_SOURCE_FD events. The only
* other thing we can legitimately receive is PORT_SOURCE_ALERT,
* but since we're not using port_alert either, we can assume
* PORT_SOURCE_FD.
*/
EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD);
}
#else
#define check_evportop(epop)
#define check_event(pevt)
#endif /* CHECK_INVARIANTS */
/*
* (Re)associates the given file descriptor with the event port. The OS events
* are specified (implicitly) from the fd_info struct.
*/
static int
reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
{
int sysevents = FDI_TO_SYSEVENTS(fdip);
if (sysevents != 0) {
if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
fd, sysevents, fdip) == -1) {
event_warn("port_associate");
return (-1);
}
}
check_evportop(epdp);
return (0);
}
/*
* Main event loop - polls port_getn for some number of events, and processes
* them.
*/
static int
evport_dispatch(struct event_base *base, struct timeval *tv)
{
int i, res;
struct evport_data *epdp = base->evbase;
port_event_t *pevtlist = epdp->ed_pevtlist;
/*
* port_getn will block until it has at least nevents events. It will
* also return how many it's given us (which may be more than we asked
* for, as long as it's less than our maximum (ed_maxevents)) in
* nevents.
*/
int nevents = 1;
/*
* We have to convert a struct timeval to a struct timespec
* (only difference is nanoseconds vs. microseconds). If no time-based
* events are active, we should wait for I/O (and tv == NULL).
*/
struct timespec ts;
struct timespec *ts_p = NULL;
if (tv != NULL) {
ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
ts_p = &ts;
}
/*
* Before doing anything else, we need to reassociate the events we hit
* last time which need reassociation. See comment at the end of the
* loop below.
*/
for (i = 0; i < epdp->ed_npending; ++i) {
struct fd_info *fdi = NULL;
const int fd = epdp->ed_pending[i];
if (fd != -1) {
/* We might have cleared out this event; we need
* to be sure that it's still set. */
fdi = evmap_io_get_fdinfo_(&base->io, fd);
}
if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
reassociate(epdp, fdi, fd);
/* epdp->ed_pending[i] = -1; */
fdi->pending_idx_plus_1 = 0;
}
}
EVBASE_RELEASE_LOCK(base, th_base_lock);
res = port_getn(epdp->ed_port, pevtlist, epdp->ed_maxevents,
(unsigned int *) &nevents, ts_p);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
if (res == -1) {
if (errno == EINTR || errno == EAGAIN) {
return (0);
} else if (errno == ETIME) {
if (nevents == 0)
return (0);
} else {
event_warn("port_getn");
return (-1);
}
}
event_debug(("%s: port_getn reports %d events", __func__, nevents));
for (i = 0; i < nevents; ++i) {
port_event_t *pevt = &pevtlist[i];
int fd = (int) pevt->portev_object;
struct fd_info *fdi = pevt->portev_user;
/*EVUTIL_ASSERT(evmap_io_get_fdinfo_(&base->io, fd) == fdi);*/
check_evportop(epdp);
check_event(pevt);
epdp->ed_pending[i] = fd;
fdi->pending_idx_plus_1 = i + 1;
/*
* Figure out what kind of event it was
* (because we have to pass this to the callback)
*/
res = 0;
if (pevt->portev_events & (POLLERR|POLLHUP)) {
res = EV_READ | EV_WRITE;
} else {
if (pevt->portev_events & POLLIN)
res |= EV_READ;
if (pevt->portev_events & POLLOUT)
res |= EV_WRITE;
}
/*
* Check for the error situations or a hangup situation
*/
if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
res |= EV_READ|EV_WRITE;
evmap_io_active_(base, fd, res);
} /* end of all events gotten */
epdp->ed_npending = nevents;
if (nevents == epdp->ed_maxevents &&
epdp->ed_maxevents < MAX_EVENTS_PER_GETN) {
/* we used all the space this time. We should be ready
* for more events next time around. */
grow(epdp, epdp->ed_maxevents * 2);
}
check_evportop(epdp);
return (0);
}
/*
* Adds the given event (so that you will be notified when it happens via
* the callback function).
*/
static int
evport_add(struct event_base *base, int fd, short old, short events, void *p)
{
struct evport_data *evpd = base->evbase;
struct fd_info *fdi = p;
check_evportop(evpd);
fdi->fdi_what |= events;
return reassociate(evpd, fdi, fd);
}
/*
* Removes the given event from the list of events to wait for.
*/
static int
evport_del(struct event_base *base, int fd, short old, short events, void *p)
{
struct evport_data *evpd = base->evbase;
struct fd_info *fdi = p;
int associated = ! fdi->pending_idx_plus_1;
check_evportop(evpd);
fdi->fdi_what &= ~(events &(EV_READ|EV_WRITE));
if (associated) {
if (!FDI_HAS_EVENTS(fdi) &&
port_dissociate(evpd->ed_port, PORT_SOURCE_FD, fd) == -1) {
/*
* Ignore EBADFD error the fd could have been closed
* before event_del() was called.
*/
if (errno != EBADFD) {
event_warn("port_dissociate");
return (-1);
}
} else {
if (FDI_HAS_EVENTS(fdi)) {
return (reassociate(evpd, fdi, fd));
}
}
} else {
if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) {
const int i = fdi->pending_idx_plus_1 - 1;
EVUTIL_ASSERT(evpd->ed_pending[i] == fd);
evpd->ed_pending[i] = -1;
fdi->pending_idx_plus_1 = 0;
}
}
return 0;
}
static void
evport_dealloc(struct event_base *base)
{
struct evport_data *evpd = base->evbase;
evsig_dealloc_(base);
close(evpd->ed_port);
if (evpd->ed_pending)
mm_free(evpd->ed_pending);
if (evpd->ed_pevtlist)
mm_free(evpd->ed_pevtlist);
mm_free(evpd);
}
#endif /* EVENT__HAVE_EVENT_PORTS */

View File

@ -0,0 +1,205 @@
/*
* 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_ */

1171
contrib/libevent/evrpc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
/*
* 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_ */

View File

@ -0,0 +1,392 @@
/*
* 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_ */

509
contrib/libevent/evthread.c Normal file
View File

@ -0,0 +1,509 @@
/*
* 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

View File

@ -0,0 +1,191 @@
/*
* 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"
/* With glibc we need to define _GNU_SOURCE to get PTHREAD_MUTEX_RECURSIVE.
* This comes from evconfig-private.h
*/
#include <pthread.h>
struct event_base;
#include "event2/thread.h"
#include <stdlib.h>
#include <string.h>
#include "mm-internal.h"
#include "evthread-internal.h"
static pthread_mutexattr_t attr_recursive;
static void *
evthread_posix_lock_alloc(unsigned locktype)
{
pthread_mutexattr_t *attr = NULL;
pthread_mutex_t *lock = mm_malloc(sizeof(pthread_mutex_t));
if (!lock)
return NULL;
if (locktype & EVTHREAD_LOCKTYPE_RECURSIVE)
attr = &attr_recursive;
if (pthread_mutex_init(lock, attr)) {
mm_free(lock);
return NULL;
}
return lock;
}
static void
evthread_posix_lock_free(void *lock_, unsigned locktype)
{
pthread_mutex_t *lock = lock_;
pthread_mutex_destroy(lock);
mm_free(lock);
}
static int
evthread_posix_lock(unsigned mode, void *lock_)
{
pthread_mutex_t *lock = lock_;
if (mode & EVTHREAD_TRY)
return pthread_mutex_trylock(lock);
else
return pthread_mutex_lock(lock);
}
static int
evthread_posix_unlock(unsigned mode, void *lock_)
{
pthread_mutex_t *lock = lock_;
return pthread_mutex_unlock(lock);
}
static unsigned long
evthread_posix_get_id(void)
{
union {
pthread_t thr;
#if EVENT__SIZEOF_PTHREAD_T > EVENT__SIZEOF_LONG
ev_uint64_t id;
#else
unsigned long id;
#endif
} r;
#if EVENT__SIZEOF_PTHREAD_T < EVENT__SIZEOF_LONG
memset(&r, 0, sizeof(r));
#endif
r.thr = pthread_self();
return (unsigned long)r.id;
}
static void *
evthread_posix_cond_alloc(unsigned condflags)
{
pthread_cond_t *cond = mm_malloc(sizeof(pthread_cond_t));
if (!cond)
return NULL;
if (pthread_cond_init(cond, NULL)) {
mm_free(cond);
return NULL;
}
return cond;
}
static void
evthread_posix_cond_free(void *cond_)
{
pthread_cond_t *cond = cond_;
pthread_cond_destroy(cond);
mm_free(cond);
}
static int
evthread_posix_cond_signal(void *cond_, int broadcast)
{
pthread_cond_t *cond = cond_;
int r;
if (broadcast)
r = pthread_cond_broadcast(cond);
else
r = pthread_cond_signal(cond);
return r ? -1 : 0;
}
static int
evthread_posix_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
{
int r;
pthread_cond_t *cond = cond_;
pthread_mutex_t *lock = lock_;
if (tv) {
struct timeval now, abstime;
struct timespec ts;
evutil_gettimeofday(&now, NULL);
evutil_timeradd(&now, tv, &abstime);
ts.tv_sec = abstime.tv_sec;
ts.tv_nsec = abstime.tv_usec*1000;
r = pthread_cond_timedwait(cond, lock, &ts);
if (r == ETIMEDOUT)
return 1;
else if (r)
return -1;
else
return 0;
} else {
r = pthread_cond_wait(cond, lock);
return r ? -1 : 0;
}
}
int
evthread_use_pthreads(void)
{
struct evthread_lock_callbacks cbs = {
EVTHREAD_LOCK_API_VERSION,
EVTHREAD_LOCKTYPE_RECURSIVE,
evthread_posix_lock_alloc,
evthread_posix_lock_free,
evthread_posix_lock,
evthread_posix_unlock
};
struct evthread_condition_callbacks cond_cbs = {
EVTHREAD_CONDITION_API_VERSION,
evthread_posix_cond_alloc,
evthread_posix_cond_free,
evthread_posix_cond_signal,
evthread_posix_cond_wait
};
/* Set ourselves up to get recursive locks. */
if (pthread_mutexattr_init(&attr_recursive))
return -1;
if (pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE))
return -1;
evthread_set_lock_callbacks(&cbs);
evthread_set_condition_callbacks(&cond_cbs);
evthread_set_id_callback(evthread_posix_get_id);
return 0;
}

View File

@ -0,0 +1,341 @@
/*
* 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;
}

2693
contrib/libevent/evutil.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,206 @@
/*
* 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.c"
#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();
}

View File

@ -0,0 +1,576 @@
/*
* 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>
/** evutil_usleep_() */
#if defined(_WIN32)
#elif defined(EVENT__HAVE_NANOSLEEP)
#elif defined(EVENT__HAVE_USLEEP)
#include <unistd.h>
#endif
#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
}
int
evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm)
{
static const char *DAYS[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *MONTHS[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
time_t t = time(NULL);
#ifndef _WIN32
struct tm sys;
#endif
/* If `tm` is null, set system's current time. */
if (tm == NULL) {
#ifdef _WIN32
/** TODO: detect _gmtime64()/_gmtime64_s() */
tm = gmtime(&t);
#else
gmtime_r(&t, &sys);
tm = &sys;
#endif
}
return evutil_snprintf(
date, datelen, "%s, %02d %s %4d %02d:%02d:%02d GMT",
DAYS[tm->tm_wday], tm->tm_mday, MONTHS[tm->tm_mon],
1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
}
/*
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

View File

@ -0,0 +1,487 @@
/* 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

View File

@ -0,0 +1,205 @@
/*
* 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 */
ev_uint16_t bind_port; /* local port for binding the src */
char *address; /* address to connect to */
ev_uint16_t 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
/* Installed when attempt to read HTTP error after write failed, see
* EVHTTP_CON_READ_ON_WRITE_ERROR */
#define EVHTTP_CON_READING_ERROR (EVHTTP_CON_AUTOFREE << 1)
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;
int flags;
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 *);
void evhttp_start_write_(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 */

5024
contrib/libevent/http.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
/*
* 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 EVENT1_EVDNS_H_INCLUDED_
#define EVENT1_EVDNS_H_INCLUDED_
/** @file evdns.h
A dns subsystem for Libevent.
The <evdns.h> header is deprecated in Libevent 2.0 and later; please
use <event2/evdns.h> instead. Depending on what functionality you
need, you may also want to include more of the other <event2/...>
headers.
*/
#include <event.h>
#include <event2/dns.h>
#include <event2/dns_compat.h>
#include <event2/dns_struct.h>
#endif /* EVENT1_EVDNS_H_INCLUDED_ */

View File

@ -0,0 +1,83 @@
/*
* 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 EVENT1_EVENT_H_INCLUDED_
#define EVENT1_EVENT_H_INCLUDED_
/** @file event.h
A library for writing event-driven network servers.
The <event.h> header is deprecated in Libevent 2.0 and later; please
use <event2/event.h> instead. Depending on what functionality you
need, you may also want to include more of the other event2/
headers.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef EVENT__HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdarg.h>
/* For int types. */
#include <evutil.h>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif
#include <event2/event_struct.h>
#include <event2/event.h>
#include <event2/event_compat.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/tag.h>
#include <event2/tag_compat.h>
#ifdef __cplusplus
}
#endif
#endif /* EVENT1_EVENT_H_INCLUDED_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
/*
* 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 EVENT2_BUFFER_COMPAT_H_INCLUDED_
#define EVENT2_BUFFER_COMPAT_H_INCLUDED_
#include <event2/visibility.h>
/** @file event2/buffer_compat.h
Obsolete and deprecated versions of the functions in buffer.h: provided
only for backward compatibility.
*/
/**
Obsolete alias for evbuffer_readln(buffer, NULL, EVBUFFER_EOL_ANY).
@deprecated This function is deprecated because its behavior is not correct
for almost any protocol, and also because it's wholly subsumed by
evbuffer_readln().
@param buffer the evbuffer to read from
@return pointer to a single line, or NULL if an error occurred
*/
EVENT2_EXPORT_SYMBOL
char *evbuffer_readline(struct evbuffer *buffer);
/** Type definition for a callback that is invoked whenever data is added or
removed from an evbuffer.
An evbuffer may have one or more callbacks set at a time. The order
in which they are executed is undefined.
A callback function may add more callbacks, or remove itself from the
list of callbacks, or add or remove data from the buffer. It may not
remove another callback from the list.
If a callback adds or removes data from the buffer or from another
buffer, this can cause a recursive invocation of your callback or
other callbacks. If you ask for an infinite loop, you might just get
one: watch out!
@param buffer the buffer whose size has changed
@param old_len the previous length of the buffer
@param new_len the current length of the buffer
@param arg a pointer to user data
*/
typedef void (*evbuffer_cb)(struct evbuffer *buffer, size_t old_len, size_t new_len, void *arg);
/**
Replace all callbacks on an evbuffer with a single new callback, or
remove them.
Subsequent calls to evbuffer_setcb() replace callbacks set by previous
calls. Setting the callback to NULL removes any previously set callback.
@deprecated This function is deprecated because it clears all previous
callbacks set on the evbuffer, which can cause confusing behavior if
multiple parts of the code all want to add their own callbacks on a
buffer. Instead, use evbuffer_add(), evbuffer_del(), and
evbuffer_setflags() to manage your own evbuffer callbacks without
interfering with callbacks set by others.
@param buffer the evbuffer to be monitored
@param cb the callback function to invoke when the evbuffer is modified,
or NULL to remove all callbacks.
@param cbarg an argument to be provided to the callback function
*/
EVENT2_EXPORT_SYMBOL
void evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg);
/**
Find a string within an evbuffer.
@param buffer the evbuffer to be searched
@param what the string to be searched for
@param len the length of the search string
@return a pointer to the beginning of the search string, or NULL if the search failed.
*/
EVENT2_EXPORT_SYMBOL
unsigned char *evbuffer_find(struct evbuffer *buffer, const unsigned char *what, size_t len);
/** deprecated in favor of calling the functions directly */
#define EVBUFFER_LENGTH(x) evbuffer_get_length(x)
/** deprecated in favor of calling the functions directly */
#define EVBUFFER_DATA(x) evbuffer_pullup((x), -1)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2007-2012 Niels Provos, Nick Mathewson
* Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_
#define EVENT2_BUFFEREVENT_COMPAT_H_INCLUDED_
#define evbuffercb bufferevent_data_cb
#define everrorcb bufferevent_event_cb
/**
Create a new bufferevent for an fd.
This function is deprecated. Use bufferevent_socket_new and
bufferevent_set_callbacks instead.
Libevent provides an abstraction on top of the regular event callbacks.
This abstraction is called a buffered event. A buffered event provides
input and output buffers that get filled and drained automatically. The
user of a buffered event no longer deals directly with the I/O, but
instead is reading from input and writing to output buffers.
Once initialized, the bufferevent structure can be used repeatedly with
bufferevent_enable() and bufferevent_disable().
When read enabled the bufferevent will try to read from the file descriptor
and call the read callback. The write callback is executed whenever the
output buffer is drained below the write low watermark, which is 0 by
default.
If multiple bases are in use, bufferevent_base_set() must be called before
enabling the bufferevent for the first time.
@deprecated This function is deprecated because it uses the current
event base, and as such can be error prone for multithreaded programs.
Use bufferevent_socket_new() instead.
@param fd the file descriptor from which data is read and written to.
This file descriptor is not allowed to be a pipe(2).
@param readcb callback to invoke when there is data to be read, or NULL if
no callback is desired
@param writecb callback to invoke when the file descriptor is ready for
writing, or NULL if no callback is desired
@param errorcb callback to invoke when there is an error on the file
descriptor
@param cbarg an argument that will be supplied to each of the callbacks
(readcb, writecb, and errorcb)
@return a pointer to a newly allocated bufferevent struct, or NULL if an
error occurred
@see bufferevent_base_set(), bufferevent_free()
*/
struct bufferevent *bufferevent_new(evutil_socket_t fd,
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
/**
Set the read and write timeout for a buffered event.
@param bufev the bufferevent to be modified
@param timeout_read the read timeout
@param timeout_write the write timeout
*/
void bufferevent_settimeout(struct bufferevent *bufev,
int timeout_read, int timeout_write);
#define EVBUFFER_READ BEV_EVENT_READING
#define EVBUFFER_WRITE BEV_EVENT_WRITING
#define EVBUFFER_EOF BEV_EVENT_EOF
#define EVBUFFER_ERROR BEV_EVENT_ERROR
#define EVBUFFER_TIMEOUT BEV_EVENT_TIMEOUT
/** macro for getting access to the input buffer of a bufferevent */
#define EVBUFFER_INPUT(x) bufferevent_get_input(x)
/** macro for getting access to the output buffer of a bufferevent */
#define EVBUFFER_OUTPUT(x) bufferevent_get_output(x)
#endif

View File

@ -0,0 +1,134 @@
/*
* 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 EVENT2_BUFFEREVENT_SSL_H_INCLUDED_
#define EVENT2_BUFFEREVENT_SSL_H_INCLUDED_
/** @file event2/bufferevent_ssl.h
OpenSSL support for bufferevents.
*/
#include <event2/visibility.h>
#include <event2/event-config.h>
#include <event2/bufferevent.h>
#include <event2/util.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is what openssl's SSL objects are underneath. */
struct ssl_st;
/**
The state of an SSL object to be used when creating a new
SSL bufferevent.
*/
enum bufferevent_ssl_state {
BUFFEREVENT_SSL_OPEN = 0,
BUFFEREVENT_SSL_CONNECTING = 1,
BUFFEREVENT_SSL_ACCEPTING = 2
};
#if defined(EVENT__HAVE_OPENSSL) || defined(EVENT_IN_DOXYGEN_)
/**
Create a new SSL bufferevent to send its data over another bufferevent.
@param base An event_base to use to detect reading and writing. It
must also be the base for the underlying bufferevent.
@param underlying A socket to use for this SSL
@param ssl A SSL* object from openssl.
@param state The current state of the SSL connection
@param options One or more bufferevent_options
@return A new bufferevent on success, or NULL on failure
*/
EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_openssl_filter_new(struct event_base *base,
struct bufferevent *underlying,
struct ssl_st *ssl,
enum bufferevent_ssl_state state,
int options);
/**
Create a new SSL bufferevent to send its data over an SSL * on a socket.
@param base An event_base to use to detect reading and writing
@param fd A socket to use for this SSL
@param ssl A SSL* object from openssl.
@param state The current state of the SSL connection
@param options One or more bufferevent_options
@return A new bufferevent on success, or NULL on failure.
*/
EVENT2_EXPORT_SYMBOL
struct bufferevent *
bufferevent_openssl_socket_new(struct event_base *base,
evutil_socket_t fd,
struct ssl_st *ssl,
enum bufferevent_ssl_state state,
int options);
/** Control how to report dirty SSL shutdowns.
If the peer (or the network, or an attacker) closes the TCP
connection before closing the SSL channel, and the protocol is SSL >= v3,
this is a "dirty" shutdown. If allow_dirty_shutdown is 0 (default),
this is reported as BEV_EVENT_ERROR.
If instead allow_dirty_shutdown=1, a dirty shutdown is reported as
BEV_EVENT_EOF.
(Note that if the protocol is < SSLv3, you will always receive
BEV_EVENT_EOF, since SSL 2 and earlier cannot distinguish a secure
connection close from a dirty one. This is one reason (among many)
not to use SSL 2.)
*/
EVENT2_EXPORT_SYMBOL
int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev);
EVENT2_EXPORT_SYMBOL
void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
int allow_dirty_shutdown);
/** Return the underlying openssl SSL * object for an SSL bufferevent. */
EVENT2_EXPORT_SYMBOL
struct ssl_st *
bufferevent_openssl_get_ssl(struct bufferevent *bufev);
/** Tells a bufferevent to begin SSL renegotiation. */
EVENT2_EXPORT_SYMBOL
int bufferevent_ssl_renegotiate(struct bufferevent *bev);
/** Return the most recent OpenSSL error reported on an SSL bufferevent. */
EVENT2_EXPORT_SYMBOL
unsigned long bufferevent_get_openssl_error(struct bufferevent *bev);
#endif
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_BUFFEREVENT_SSL_H_INCLUDED_ */

View File

@ -0,0 +1,116 @@
/*
* 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 EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_
#define EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_
/** @file event2/bufferevent_struct.h
Data structures for bufferevents. Using these structures may hurt forward
compatibility with later versions of Libevent: be careful!
@deprecated Use of bufferevent_struct.h is completely deprecated; these
structures are only exposed for backward compatibility with programs
written before Libevent 2.0 that used them.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/* For struct event */
#include <event2/event_struct.h>
struct event_watermark {
size_t low;
size_t high;
};
/**
Shared implementation of a bufferevent.
This type is exposed only because it was exposed in previous versions,
and some people's code may rely on manipulating it. Otherwise, you
should really not rely on the layout, size, or contents of this structure:
it is fairly volatile, and WILL change in future versions of the code.
**/
struct bufferevent {
/** Event base for which this bufferevent was created. */
struct event_base *ev_base;
/** Pointer to a table of function pointers to set up how this
bufferevent behaves. */
const struct bufferevent_ops *be_ops;
/** A read event that triggers when a timeout has happened or a socket
is ready to read data. Only used by some subtypes of
bufferevent. */
struct event ev_read;
/** A write event that triggers when a timeout has happened or a socket
is ready to write data. Only used by some subtypes of
bufferevent. */
struct event ev_write;
/** An input buffer. Only the bufferevent is allowed to add data to
this buffer, though the user is allowed to drain it. */
struct evbuffer *input;
/** An input buffer. Only the bufferevent is allowed to drain data
from this buffer, though the user is allowed to add it. */
struct evbuffer *output;
struct event_watermark wm_read;
struct event_watermark wm_write;
bufferevent_data_cb readcb;
bufferevent_data_cb writecb;
/* This should be called 'eventcb', but renaming it would break
* backward compatibility */
bufferevent_event_cb errorcb;
void *cbarg;
struct timeval timeout_read;
struct timeval timeout_write;
/** Events that are currently enabled: currently EV_READ and EV_WRITE
are supported. */
short enabled;
};
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_BUFFEREVENT_STRUCT_H_INCLUDED_ */

View File

@ -0,0 +1,717 @@
/*
* 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.
*/
/*
* The original DNS code is due to Adam Langley with heavy
* modifications by Nick Mathewson. Adam put his DNS software in the
* public domain. You can find his original copyright below. Please,
* aware that the code as part of Libevent is governed by the 3-clause
* BSD license above.
*
* This software is Public Domain. To view a copy of the public domain dedication,
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
*
* I ask and expect, but do not require, that all derivative works contain an
* attribution similar to:
* Parts developed by Adam Langley <agl@imperialviolet.org>
*
* You may wish to replace the word "Parts" with something else depending on
* the amount of original code.
*
* (Derivative works does not include programs which link against, run or include
* the source verbatim in their source distributions)
*/
/** @file event2/dns.h
*
* Welcome, gentle reader
*
* Async DNS lookups are really a whole lot harder than they should be,
* mostly stemming from the fact that the libc resolver has never been
* very good at them. Before you use this library you should see if libc
* can do the job for you with the modern async call getaddrinfo_a
* (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
* please continue.
*
* The library keeps track of the state of nameservers and will avoid
* them when they go down. Otherwise it will round robin between them.
*
* Quick start guide:
* #include "evdns.h"
* void callback(int result, char type, int count, int ttl,
* void *addresses, void *arg);
* evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
* evdns_resolve("www.hostname.com", 0, callback, NULL);
*
* When the lookup is complete the callback function is called. The
* first argument will be one of the DNS_ERR_* defines in evdns.h.
* Hopefully it will be DNS_ERR_NONE, in which case type will be
* DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
* which the data can be cached for (in seconds), addresses will point
* to an array of uint32_t's and arg will be whatever you passed to
* evdns_resolve.
*
* Searching:
*
* In order for this library to be a good replacement for glibc's resolver it
* supports searching. This involves setting a list of default domains, in
* which names will be queried for. The number of dots in the query name
* determines the order in which this list is used.
*
* Searching appears to be a single lookup from the point of view of the API,
* although many DNS queries may be generated from a single call to
* evdns_resolve. Searching can also drastically slow down the resolution
* of names.
*
* To disable searching:
* 1. Never set it up. If you never call evdns_resolv_conf_parse or
* evdns_search_add then no searching will occur.
*
* 2. If you do call evdns_resolv_conf_parse then don't pass
* DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
*
* 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
*
* The order of searches depends on the number of dots in the name. If the
* number is greater than the ndots setting then the names is first tried
* globally. Otherwise each search domain is appended in turn.
*
* The ndots setting can either be set from a resolv.conf, or by calling
* evdns_search_ndots_set.
*
* For example, with ndots set to 1 (the default) and a search domain list of
* ["myhome.net"]:
* Query: www
* Order: www.myhome.net, www.
*
* Query: www.abc
* Order: www.abc., www.abc.myhome.net
*
* Internals:
*
* Requests are kept in two queues. The first is the inflight queue. In
* this queue requests have an allocated transaction id and nameserver.
* They will soon be transmitted if they haven't already been.
*
* The second is the waiting queue. The size of the inflight ring is
* limited and all other requests wait in waiting queue for space. This
* bounds the number of concurrent requests so that we don't flood the
* nameserver. Several algorithms require a full walk of the inflight
* queue and so bounding its size keeps thing going nicely under huge
* (many thousands of requests) loads.
*
* If a nameserver loses too many requests it is considered down and we
* try not to use it. After a while we send a probe to that nameserver
* (a lookup for google.com) and, if it replies, we consider it working
* again. If the nameserver fails a probe we wait longer to try again
* with the next probe.
*/
#ifndef EVENT2_DNS_H_INCLUDED_
#define EVENT2_DNS_H_INCLUDED_
#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
#endif
/* For integer types. */
#include <event2/util.h>
/** Error codes 0-5 are as described in RFC 1035. */
#define DNS_ERR_NONE 0
/** The name server was unable to interpret the query */
#define DNS_ERR_FORMAT 1
/** The name server was unable to process this query due to a problem with the
* name server */
#define DNS_ERR_SERVERFAILED 2
/** The domain name does not exist */
#define DNS_ERR_NOTEXIST 3
/** The name server does not support the requested kind of query */
#define DNS_ERR_NOTIMPL 4
/** The name server refuses to reform the specified operation for policy
* reasons */
#define DNS_ERR_REFUSED 5
/** The reply was truncated or ill-formatted */
#define DNS_ERR_TRUNCATED 65
/** An unknown error occurred */
#define DNS_ERR_UNKNOWN 66
/** Communication with the server timed out */
#define DNS_ERR_TIMEOUT 67
/** The request was canceled because the DNS subsystem was shut down. */
#define DNS_ERR_SHUTDOWN 68
/** The request was canceled via a call to evdns_cancel_request */
#define DNS_ERR_CANCEL 69
/** There were no answers and no error condition in the DNS packet.
* This can happen when you ask for an address that exists, but a record
* type that doesn't. */
#define DNS_ERR_NODATA 70
#define DNS_IPv4_A 1
#define DNS_PTR 2
#define DNS_IPv6_AAAA 3
#define DNS_QUERY_NO_SEARCH 1
#define DNS_OPTION_SEARCH 1
#define DNS_OPTION_NAMESERVERS 2
#define DNS_OPTION_MISC 4
#define DNS_OPTION_HOSTSFILE 8
#define DNS_OPTIONS_ALL 15
/* Obsolete name for DNS_QUERY_NO_SEARCH */
#define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH
/**
* The callback that contains the results from a lookup.
* - result is one of the DNS_ERR_* values (DNS_ERR_NONE for success)
* - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
* - count contains the number of addresses of form type
* - ttl is the number of seconds the resolution may be cached for.
* - addresses needs to be cast according to type. It will be an array of
* 4-byte sequences for ipv4, or an array of 16-byte sequences for ipv6,
* or a nul-terminated string for PTR.
*/
typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
struct evdns_base;
struct event_base;
/** Flag for evdns_base_new: process resolv.conf. */
#define EVDNS_BASE_INITIALIZE_NAMESERVERS 1
/** Flag for evdns_base_new: Do not prevent the libevent event loop from
* exiting when we have no active dns requests. */
#define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000
/**
Initialize the asynchronous DNS library.
This function initializes support for non-blocking name resolution by
calling evdns_resolv_conf_parse() on UNIX and
evdns_config_windows_nameservers() on Windows.
@param event_base the event base to associate the dns client with
@param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS|
EVDNS_BASE_DISABLE_WHEN_INACTIVE
@return evdns_base object if successful, or NULL if an error occurred.
@see evdns_base_free()
*/
EVENT2_EXPORT_SYMBOL
struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers);
/**
Shut down the asynchronous DNS resolver and terminate all active requests.
If the 'fail_requests' option is enabled, all active requests will return
an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
the requests will be silently discarded.
@param evdns_base the evdns base to free
@param fail_requests if zero, active requests will be aborted; if non-zero,
active requests will return DNS_ERR_SHUTDOWN.
@see evdns_base_new()
*/
EVENT2_EXPORT_SYMBOL
void evdns_base_free(struct evdns_base *base, int fail_requests);
/**
Remove all hosts entries that have been loaded into the event_base via
evdns_base_load_hosts or via event_base_resolv_conf_parse.
@param evdns_base the evdns base to remove outdated host addresses from
*/
EVENT2_EXPORT_SYMBOL
void evdns_base_clear_host_addresses(struct evdns_base *base);
/**
Convert a DNS error code to a string.
@param err the DNS error code
@return a string containing an explanation of the error code
*/
EVENT2_EXPORT_SYMBOL
const char *evdns_err_to_string(int err);
/**
Add a nameserver.
The address should be an IPv4 address in network byte order.
The type of address is chosen so that it matches in_addr.s_addr.
@param base the evdns_base to which to add the name server
@param address an IP address in network byte order
@return 0 if successful, or -1 if an error occurred
@see evdns_base_nameserver_ip_add()
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_nameserver_add(struct evdns_base *base,
unsigned long int address);
/**
Get the number of configured nameservers.
This returns the number of configured nameservers (not necessarily the
number of running nameservers). This is useful for double-checking
whether our calls to the various nameserver configuration functions
have been successful.
@param base the evdns_base to which to apply this operation
@return the number of configured nameservers
@see evdns_base_nameserver_add()
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_count_nameservers(struct evdns_base *base);
/**
Remove all configured nameservers, and suspend all pending resolves.
Resolves will not necessarily be re-attempted until evdns_base_resume() is called.
@param base the evdns_base to which to apply this operation
@return 0 if successful, or -1 if an error occurred
@see evdns_base_resume()
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_clear_nameservers_and_suspend(struct evdns_base *base);
/**
Resume normal operation and continue any suspended resolve requests.
Re-attempt resolves left in limbo after an earlier call to
evdns_base_clear_nameservers_and_suspend().
@param base the evdns_base to which to apply this operation
@return 0 if successful, or -1 if an error occurred
@see evdns_base_clear_nameservers_and_suspend()
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_resume(struct evdns_base *base);
/**
Add a nameserver by string address.
This function parses a n IPv4 or IPv6 address from a string and adds it as a
nameserver. It supports the following formats:
- [IPv6Address]:port
- [IPv6Address]
- IPv6Address
- IPv4Address:port
- IPv4Address
If no port is specified, it defaults to 53.
@param base the evdns_base to which to apply this operation
@return 0 if successful, or -1 if an error occurred
@see evdns_base_nameserver_add()
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_nameserver_ip_add(struct evdns_base *base,
const char *ip_as_string);
/**
Add a nameserver by sockaddr.
**/
EVENT2_EXPORT_SYMBOL
int
evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
const struct sockaddr *sa, ev_socklen_t len, unsigned flags);
struct evdns_request;
/**
Lookup an A record for a given name.
@param base the evdns_base to which to apply this operation
@param name a DNS hostname
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr);
/**
Lookup an AAAA record for a given name.
@param base the evdns_base to which to apply this operation
@param name a DNS hostname
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_ipv6(struct evdns_base *base, const char *name, int flags, evdns_callback_type callback, void *ptr);
struct in_addr;
struct in6_addr;
/**
Lookup a PTR record for a given IP address.
@param base the evdns_base to which to apply this operation
@param in an IPv4 address
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
EVENT2_EXPORT_SYMBOL
struct evdns_request *evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
/**
Lookup a PTR record for a given IPv6 address.
@param base the evdns_base to which to apply this operation
@param in an IPv6 address
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return an evdns_request object if successful, or NULL if an error occurred.
@see evdns_resolve_reverse_ipv6(), evdns_cancel_request()
*/
EVENT2_EXPORT_SYMBOL
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);
/**
Cancels a pending DNS resolution request.
@param base the evdns_base that was used to make the request
@param req the evdns_request that was returned by calling a resolve function
@see evdns_base_resolve_ipv4(), evdns_base_resolve_ipv6, evdns_base_resolve_reverse
*/
EVENT2_EXPORT_SYMBOL
void evdns_cancel_request(struct evdns_base *base, struct evdns_request *req);
/**
Set the value of a configuration option.
The currently available configuration options are:
ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case,
bind-to, initial-probe-timeout, getaddrinfo-allow-skew.
In versions before Libevent 2.0.3-alpha, the option name needed to end with
a colon.
@param base the evdns_base to which to apply this operation
@param option the name of the configuration option to be modified
@param val the value to be set
@return 0 if successful, or -1 if an error occurred
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val);
/**
Parse a resolv.conf file.
The 'flags' parameter determines what information is parsed from the
resolv.conf file. See the man page for resolv.conf for the format of this
file.
The following directives are not parsed from the file: sortlist, rotate,
no-check-names, inet6, debug.
If this function encounters an error, the possible return values are: 1 =
failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
memory, 5 = short read from file, 6 = no nameservers listed in the file
@param base the evdns_base to which to apply this operation
@param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL
@param filename the path to the resolv.conf file
@return 0 if successful, or various positive error codes if an error
occurred (see above)
@see resolv.conf(3), evdns_config_windows_nameservers()
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename);
/**
Load an /etc/hosts-style file from 'hosts_fname' into 'base'.
If hosts_fname is NULL, add minimal entries for localhost, and nothing
else.
Note that only evdns_getaddrinfo uses the /etc/hosts entries.
This function does not replace previously loaded hosts entries; to do that,
call evdns_base_clear_host_addresses first.
Return 0 on success, negative on failure.
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
/**
Obtain nameserver information using the Windows API.
Attempt to configure a set of nameservers based on platform settings on
a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
looks in the registry.
@return 0 if successful, or -1 if an error occurred
@see evdns_resolv_conf_parse()
*/
#ifdef _WIN32
EVENT2_EXPORT_SYMBOL
int evdns_base_config_windows_nameservers(struct evdns_base *);
#define EVDNS_BASE_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
#endif
/**
Clear the list of search domains.
*/
EVENT2_EXPORT_SYMBOL
void evdns_base_search_clear(struct evdns_base *base);
/**
Add a domain to the list of search domains
@param domain the domain to be added to the search list
*/
EVENT2_EXPORT_SYMBOL
void evdns_base_search_add(struct evdns_base *base, const char *domain);
/**
Set the 'ndots' parameter for searches.
Sets the number of dots which, when found in a name, causes
the first query to be without any search domain.
@param ndots the new ndots parameter
*/
EVENT2_EXPORT_SYMBOL
void evdns_base_search_ndots_set(struct evdns_base *base, const int ndots);
/**
A callback that is invoked when a log message is generated
@param is_warning indicates if the log message is a 'warning'
@param msg the content of the log message
*/
typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
/**
Set the callback function to handle DNS log messages. If this
callback is not set, evdns log messages are handled with the regular
Libevent logging system.
@param fn the callback to be invoked when a log message is generated
*/
EVENT2_EXPORT_SYMBOL
void evdns_set_log_fn(evdns_debug_log_fn_type fn);
/**
Set a callback that will be invoked to generate transaction IDs. By
default, we pick transaction IDs based on the current clock time, which
is bad for security.
@param fn the new callback, or NULL to use the default.
NOTE: This function has no effect in Libevent 2.0.4-alpha and later,
since Libevent now provides its own secure RNG.
*/
EVENT2_EXPORT_SYMBOL
void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
/**
Set a callback used to generate random bytes. By default, we use
the same function as passed to evdns_set_transaction_id_fn to generate
bytes two at a time. If a function is provided here, it's also used
to generate transaction IDs.
NOTE: This function has no effect in Libevent 2.0.4-alpha and later,
since Libevent now provides its own secure RNG.
*/
EVENT2_EXPORT_SYMBOL
void evdns_set_random_bytes_fn(void (*fn)(char *, size_t));
/*
* Functions used to implement a DNS server.
*/
struct evdns_server_request;
struct evdns_server_question;
/**
A callback to implement a DNS server. The callback function receives a DNS
request. It should then optionally add a number of answers to the reply
using the evdns_server_request_add_*_reply functions, before calling either
evdns_server_request_respond to send the reply back, or
evdns_server_request_drop to decline to answer the request.
@param req A newly received request
@param user_data A pointer that was passed to
evdns_add_server_port_with_base().
*/
typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
#define EVDNS_ANSWER_SECTION 0
#define EVDNS_AUTHORITY_SECTION 1
#define EVDNS_ADDITIONAL_SECTION 2
#define EVDNS_TYPE_A 1
#define EVDNS_TYPE_NS 2
#define EVDNS_TYPE_CNAME 5
#define EVDNS_TYPE_SOA 6
#define EVDNS_TYPE_PTR 12
#define EVDNS_TYPE_MX 15
#define EVDNS_TYPE_TXT 16
#define EVDNS_TYPE_AAAA 28
#define EVDNS_QTYPE_AXFR 252
#define EVDNS_QTYPE_ALL 255
#define EVDNS_CLASS_INET 1
/* flags that can be set in answers; as part of the err parameter */
#define EVDNS_FLAGS_AA 0x400
#define EVDNS_FLAGS_RD 0x080
/** Create a new DNS server port.
@param base The event base to handle events for the server port.
@param socket A UDP socket to accept DNS requests.
@param flags Always 0 for now.
@param callback A function to invoke whenever we get a DNS request
on the socket.
@param user_data Data to pass to the callback.
@return an evdns_server_port structure for this server port.
*/
EVENT2_EXPORT_SYMBOL
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 callback, void *user_data);
/** Close down a DNS server port, and free associated structures. */
EVENT2_EXPORT_SYMBOL
void evdns_close_server_port(struct evdns_server_port *port);
/** Sets some flags in a reply we're building.
Allows setting of the AA or RD flags
*/
EVENT2_EXPORT_SYMBOL
void evdns_server_request_set_flags(struct evdns_server_request *req, int flags);
/* Functions to add an answer to an in-progress DNS reply.
*/
EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
EVENT2_EXPORT_SYMBOL
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);
EVENT2_EXPORT_SYMBOL
int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
/**
Send back a response to a DNS request, and free the request structure.
*/
EVENT2_EXPORT_SYMBOL
int evdns_server_request_respond(struct evdns_server_request *req, int err);
/**
Free a DNS request without sending back a reply.
*/
EVENT2_EXPORT_SYMBOL
int evdns_server_request_drop(struct evdns_server_request *req);
struct sockaddr;
/**
Get the address that made a DNS request.
*/
EVENT2_EXPORT_SYMBOL
int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len);
/** Callback for evdns_getaddrinfo. */
typedef void (*evdns_getaddrinfo_cb)(int result, struct evutil_addrinfo *res, void *arg);
struct evdns_base;
struct evdns_getaddrinfo_request;
/** Make a non-blocking getaddrinfo request using the dns_base in 'dns_base'.
*
* If we can answer the request immediately (with an error or not!), then we
* invoke cb immediately and return NULL. Otherwise we return
* an evdns_getaddrinfo_request and invoke cb later.
*
* When the callback is invoked, we pass as its first argument the error code
* that getaddrinfo would return (or 0 for no error). As its second argument,
* we pass the evutil_addrinfo structures we found (or NULL on error). We
* pass 'arg' as the third argument.
*
* Limitations:
*
* - The AI_V4MAPPED and AI_ALL flags are not currently implemented.
* - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0.
* - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0.
*/
EVENT2_EXPORT_SYMBOL
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);
/* Cancel an in-progress evdns_getaddrinfo. This MUST NOT be called after the
* getaddrinfo's callback has been invoked. The resolves will be canceled,
* and the callback will be invoked with the error EVUTIL_EAI_CANCEL. */
EVENT2_EXPORT_SYMBOL
void evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *req);
/**
Retrieve the address of the 'idx'th configured nameserver.
@param base The evdns_base to examine.
@param idx The index of the nameserver to get the address of.
@param sa A location to receive the server's address.
@param len The number of bytes available at sa.
@return the number of bytes written into sa on success. On failure, returns
-1 if idx is greater than the number of configured nameservers, or a
value greater than 'len' if len was not high enough.
*/
EVENT2_EXPORT_SYMBOL
int evdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
struct sockaddr *sa, ev_socklen_t len);
#ifdef __cplusplus
}
#endif
#endif /* !EVENT2_DNS_H_INCLUDED_ */

View File

@ -0,0 +1,336 @@
/*
* 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 EVENT2_DNS_COMPAT_H_INCLUDED_
#define EVENT2_DNS_COMPAT_H_INCLUDED_
/** @file event2/dns_compat.h
Potentially non-threadsafe versions of the functions in dns.h: provided
only for backwards compatibility.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/**
Initialize the asynchronous DNS library.
This function initializes support for non-blocking name resolution by
calling evdns_resolv_conf_parse() on UNIX and
evdns_config_windows_nameservers() on Windows.
@deprecated This function is deprecated because it always uses the current
event base, and is easily confused by multiple calls to event_init(), and
so is not safe for multithreaded use. Additionally, it allocates a global
structure that only one thread can use. The replacement is
evdns_base_new().
@return 0 if successful, or -1 if an error occurred
@see evdns_shutdown()
*/
int evdns_init(void);
struct evdns_base;
/**
Return the global evdns_base created by event_init() and used by the other
deprecated functions.
@deprecated This function is deprecated because use of the global
evdns_base is error-prone.
*/
struct evdns_base *evdns_get_global_base(void);
/**
Shut down the asynchronous DNS resolver and terminate all active requests.
If the 'fail_requests' option is enabled, all active requests will return
an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
the requests will be silently discarded.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_shutdown().
@param fail_requests if zero, active requests will be aborted; if non-zero,
active requests will return DNS_ERR_SHUTDOWN.
@see evdns_init()
*/
void evdns_shutdown(int fail_requests);
/**
Add a nameserver.
The address should be an IPv4 address in network byte order.
The type of address is chosen so that it matches in_addr.s_addr.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_nameserver_add().
@param address an IP address in network byte order
@return 0 if successful, or -1 if an error occurred
@see evdns_nameserver_ip_add()
*/
int evdns_nameserver_add(unsigned long int address);
/**
Get the number of configured nameservers.
This returns the number of configured nameservers (not necessarily the
number of running nameservers). This is useful for double-checking
whether our calls to the various nameserver configuration functions
have been successful.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_count_nameservers().
@return the number of configured nameservers
@see evdns_nameserver_add()
*/
int evdns_count_nameservers(void);
/**
Remove all configured nameservers, and suspend all pending resolves.
Resolves will not necessarily be re-attempted until evdns_resume() is called.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_clear_nameservers_and_suspend().
@return 0 if successful, or -1 if an error occurred
@see evdns_resume()
*/
int evdns_clear_nameservers_and_suspend(void);
/**
Resume normal operation and continue any suspended resolve requests.
Re-attempt resolves left in limbo after an earlier call to
evdns_clear_nameservers_and_suspend().
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_resume().
@return 0 if successful, or -1 if an error occurred
@see evdns_clear_nameservers_and_suspend()
*/
int evdns_resume(void);
/**
Add a nameserver.
This wraps the evdns_nameserver_add() function by parsing a string as an IP
address and adds it as a nameserver.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_nameserver_ip_add().
@return 0 if successful, or -1 if an error occurred
@see evdns_nameserver_add()
*/
int evdns_nameserver_ip_add(const char *ip_as_string);
/**
Lookup an A record for a given name.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_resolve_ipv4().
@param name a DNS hostname
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return 0 if successful, or -1 if an error occurred
@see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
*/
int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
/**
Lookup an AAAA record for a given name.
@param name a DNS hostname
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return 0 if successful, or -1 if an error occurred
@see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
*/
int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
struct in_addr;
struct in6_addr;
/**
Lookup a PTR record for a given IP address.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_resolve_reverse().
@param in an IPv4 address
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return 0 if successful, or -1 if an error occurred
@see evdns_resolve_reverse_ipv6()
*/
int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
/**
Lookup a PTR record for a given IPv6 address.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_resolve_reverse_ipv6().
@param in an IPv6 address
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
@param callback a callback function to invoke when the request is completed
@param ptr an argument to pass to the callback function
@return 0 if successful, or -1 if an error occurred
@see evdns_resolve_reverse_ipv6()
*/
int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
/**
Set the value of a configuration option.
The currently available configuration options are:
ndots, timeout, max-timeouts, max-inflight, and attempts
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_set_option().
@param option the name of the configuration option to be modified
@param val the value to be set
@param flags Ignored.
@return 0 if successful, or -1 if an error occurred
*/
int evdns_set_option(const char *option, const char *val, int flags);
/**
Parse a resolv.conf file.
The 'flags' parameter determines what information is parsed from the
resolv.conf file. See the man page for resolv.conf for the format of this
file.
The following directives are not parsed from the file: sortlist, rotate,
no-check-names, inet6, debug.
If this function encounters an error, the possible return values are: 1 =
failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
memory, 5 = short read from file, 6 = no nameservers listed in the file
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_resolv_conf_parse().
@param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
DNS_OPTIONS_ALL
@param filename the path to the resolv.conf file
@return 0 if successful, or various positive error codes if an error
occurred (see above)
@see resolv.conf(3), evdns_config_windows_nameservers()
*/
int evdns_resolv_conf_parse(int flags, const char *const filename);
/**
Clear the list of search domains.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_search_clear().
*/
void evdns_search_clear(void);
/**
Add a domain to the list of search domains
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_search_add().
@param domain the domain to be added to the search list
*/
void evdns_search_add(const char *domain);
/**
Set the 'ndots' parameter for searches.
Sets the number of dots which, when found in a name, causes
the first query to be without any search domain.
@deprecated This function is deprecated because it does not allow the
caller to specify which evdns_base it applies to. The recommended
function is evdns_base_search_ndots_set().
@param ndots the new ndots parameter
*/
void evdns_search_ndots_set(const int ndots);
/**
As evdns_server_new_with_base.
@deprecated This function is deprecated because it does not allow the
caller to specify which even_base it uses. The recommended
function is evdns_add_server_port_with_base().
*/
struct evdns_server_port *evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type callback, void *user_data);
#ifdef _WIN32
int evdns_config_windows_nameservers(void);
#define EVDNS_CONFIG_WINDOWS_NAMESERVERS_IMPLEMENTED
#endif
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */

View File

@ -0,0 +1,80 @@
/*
* 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 EVENT2_DNS_STRUCT_H_INCLUDED_
#define EVENT2_DNS_STRUCT_H_INCLUDED_
/** @file event2/dns_struct.h
Data structures for dns. Using these structures may hurt forward
compatibility with later versions of Libevent: be careful!
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/*
* Structures used to implement a DNS server.
*/
struct evdns_server_request {
int flags;
int nquestions;
struct evdns_server_question **questions;
};
struct evdns_server_question {
int type;
#ifdef __cplusplus
int dns_question_class;
#else
/* You should refer to this field as "dns_question_class". The
* name "class" works in C for backward compatibility, and will be
* removed in a future version. (1.5 or later). */
int class;
#define dns_question_class class
#endif
char name[1];
};
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_DNS_STRUCT_H_INCLUDED_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,230 @@
/*
* 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 EVENT2_EVENT_COMPAT_H_INCLUDED_
#define EVENT2_EVENT_COMPAT_H_INCLUDED_
/** @file event2/event_compat.h
Potentially non-threadsafe versions of the functions in event.h: provided
only for backwards compatibility.
In the oldest versions of Libevent, event_base was not a first-class
structure. Instead, there was a single event base that every function
manipulated. Later, when separate event bases were added, the old functions
that didn't take an event_base argument needed to work by manipulating the
"current" event base. This could lead to thread-safety issues, and obscure,
hard-to-diagnose bugs.
@deprecated All functions in this file are by definition deprecated.
*/
#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/**
Initialize the event API.
The event API needs to be initialized with event_init() before it can be
used. Sets the global current base that gets used for events that have no
base associated with them.
@deprecated This function is deprecated because it replaces the "current"
event_base, and is totally unsafe for multithreaded use. The replacement
is event_base_new().
@see event_base_set(), event_base_new()
*/
EVENT2_EXPORT_SYMBOL
struct event_base *event_init(void);
/**
Loop to process events.
Like event_base_dispatch(), but uses the "current" base.
@deprecated This function is deprecated because it is easily confused by
multiple calls to event_init(), and because it is not safe for
multithreaded use. The replacement is event_base_dispatch().
@see event_base_dispatch(), event_init()
*/
EVENT2_EXPORT_SYMBOL
int event_dispatch(void);
/**
Handle events.
This function behaves like event_base_loop(), but uses the "current" base
@deprecated This function is deprecated because it uses the event base from
the last call to event_init, and is therefore not safe for multithreaded
use. The replacement is event_base_loop().
@see event_base_loop(), event_init()
*/
EVENT2_EXPORT_SYMBOL
int event_loop(int);
/**
Exit the event loop after the specified time.
This function behaves like event_base_loopexit(), except that it uses the
"current" base.
@deprecated This function is deprecated because it uses the event base from
the last call to event_init, and is therefore not safe for multithreaded
use. The replacement is event_base_loopexit().
@see event_init, event_base_loopexit()
*/
EVENT2_EXPORT_SYMBOL
int event_loopexit(const struct timeval *);
/**
Abort the active event_loop() immediately.
This function behaves like event_base_loopbreakt(), except that it uses the
"current" base.
@deprecated This function is deprecated because it uses the event base from
the last call to event_init, and is therefore not safe for multithreaded
use. The replacement is event_base_loopbreak().
@see event_base_loopbreak(), event_init()
*/
EVENT2_EXPORT_SYMBOL
int event_loopbreak(void);
/**
Schedule a one-time event to occur.
@deprecated This function is obsolete, and has been replaced by
event_base_once(). Its use is deprecated because it relies on the
"current" base configured by event_init().
@see event_base_once()
*/
EVENT2_EXPORT_SYMBOL
int event_once(evutil_socket_t , short,
void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
/**
Get the kernel event notification mechanism used by Libevent.
@deprecated This function is obsolete, and has been replaced by
event_base_get_method(). Its use is deprecated because it relies on the
"current" base configured by event_init().
@see event_base_get_method()
*/
EVENT2_EXPORT_SYMBOL
const char *event_get_method(void);
/**
Set the number of different event priorities.
@deprecated This function is deprecated because it is easily confused by
multiple calls to event_init(), and because it is not safe for
multithreaded use. The replacement is event_base_priority_init().
@see event_base_priority_init()
*/
EVENT2_EXPORT_SYMBOL
int event_priority_init(int);
/**
Prepare an event structure to be added.
@deprecated event_set() is not recommended for new code, because it requires
a subsequent call to event_base_set() to be safe under most circumstances.
Use event_assign() or event_new() instead.
*/
EVENT2_EXPORT_SYMBOL
void event_set(struct event *, evutil_socket_t, short, void (*)(evutil_socket_t, short, void *), void *);
#define evtimer_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg))
#define evsignal_set(ev, x, cb, arg) \
event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
/**
@name timeout_* macros
@deprecated These macros are deprecated because their naming is inconsistent
with the rest of Libevent. Use the evtimer_* macros instead.
@{
*/
#define timeout_add(ev, tv) event_add((ev), (tv))
#define timeout_set(ev, cb, arg) event_set((ev), -1, 0, (cb), (arg))
#define timeout_del(ev) event_del(ev)
#define timeout_pending(ev, tv) event_pending((ev), EV_TIMEOUT, (tv))
#define timeout_initialized(ev) event_initialized(ev)
/**@}*/
/**
@name signal_* macros
@deprecated These macros are deprecated because their naming is inconsistent
with the rest of Libevent. Use the evsignal_* macros instead.
@{
*/
#define signal_add(ev, tv) event_add((ev), (tv))
#define signal_set(ev, x, cb, arg) \
event_set((ev), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
#define signal_del(ev) event_del(ev)
#define signal_pending(ev, tv) event_pending((ev), EV_SIGNAL, (tv))
#define signal_initialized(ev) event_initialized(ev)
/**@}*/
#ifndef EVENT_FD
/* These macros are obsolete; use event_get_fd and event_get_signal instead. */
#define EVENT_FD(ev) ((int)event_get_fd(ev))
#define EVENT_SIGNAL(ev) event_get_signal(ev)
#endif
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */

View File

@ -0,0 +1,180 @@
/*
* 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 EVENT2_EVENT_STRUCT_H_INCLUDED_
#define EVENT2_EVENT_STRUCT_H_INCLUDED_
/** @file event2/event_struct.h
Structures used by event.h. Using these structures directly WILL harm
forward compatibility: be careful.
No field declared in this file should be used directly in user code. Except
for historical reasons, these fields would not be exposed at all.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/* For evkeyvalq */
#include <event2/keyvalq_struct.h>
#define EVLIST_TIMEOUT 0x01
#define EVLIST_INSERTED 0x02
#define EVLIST_SIGNAL 0x04
#define EVLIST_ACTIVE 0x08
#define EVLIST_INTERNAL 0x10
#define EVLIST_ACTIVE_LATER 0x20
#define EVLIST_FINALIZING 0x40
#define EVLIST_INIT 0x80
#define EVLIST_ALL 0xff
/* Fix so that people don't have to run with <sys/queue.h> */
#ifndef TAILQ_ENTRY
#define EVENT_DEFINED_TQENTRY_
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
#endif /* !TAILQ_ENTRY */
#ifndef TAILQ_HEAD
#define EVENT_DEFINED_TQHEAD_
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; \
struct type **tqh_last; \
}
#endif
/* Fix so that people don't have to run with <sys/queue.h> */
#ifndef LIST_ENTRY
#define EVENT_DEFINED_LISTENTRY_
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
#endif /* !LIST_ENTRY */
#ifndef LIST_HEAD
#define EVENT_DEFINED_LISTHEAD_
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#endif /* !LIST_HEAD */
struct event;
struct event_callback {
TAILQ_ENTRY(event_callback) evcb_active_next;
short evcb_flags;
ev_uint8_t evcb_pri; /* smaller numbers are higher priority */
ev_uint8_t evcb_closure;
/* allows us to adopt for different types of events */
union {
void (*evcb_callback)(evutil_socket_t, short, void *);
void (*evcb_selfcb)(struct event_callback *, void *);
void (*evcb_evfinalize)(struct event *, void *);
void (*evcb_cbfinalize)(struct event_callback *, void *);
} evcb_cb_union;
void *evcb_arg;
};
struct event_base;
struct event {
struct event_callback ev_evcallback;
/* for managing timeouts */
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;
int min_heap_idx;
} ev_timeout_pos;
evutil_socket_t ev_fd;
struct event_base *ev_base;
union {
/* used for io events */
struct {
LIST_ENTRY (event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
struct {
LIST_ENTRY (event) ev_signal_next;
short ev_ncalls;
/* Allows deletes in callback */
short *ev_pncalls;
} ev_signal;
} ev_;
short ev_events;
short ev_res; /* result passed to event callback */
struct timeval ev_timeout;
};
TAILQ_HEAD (event_list, event);
#ifdef EVENT_DEFINED_TQENTRY_
#undef TAILQ_ENTRY
#endif
#ifdef EVENT_DEFINED_TQHEAD_
#undef TAILQ_HEAD
#endif
LIST_HEAD (event_dlist, event);
#ifdef EVENT_DEFINED_LISTENTRY_
#undef LIST_ENTRY
#endif
#ifdef EVENT_DEFINED_LISTHEAD_
#undef LIST_HEAD
#endif
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_EVENT_STRUCT_H_INCLUDED_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
/*
* 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 EVENT2_HTTP_COMPAT_H_INCLUDED_
#define EVENT2_HTTP_COMPAT_H_INCLUDED_
/** @file event2/http_compat.h
Potentially non-threadsafe versions of the functions in http.h: provided
only for backwards compatibility.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/**
* Start an HTTP server on the specified address and port
*
* @deprecated It does not allow an event base to be specified
*
* @param address the address to which the HTTP server should be bound
* @param port the port number on which the HTTP server should listen
* @return an struct evhttp object
*/
struct evhttp *evhttp_start(const char *address, ev_uint16_t port);
/**
* A connection object that can be used to for making HTTP requests. The
* connection object tries to establish the connection when it is given an
* http request object.
*
* @deprecated It does not allow an event base to be specified
*/
struct evhttp_connection *evhttp_connection_new(
const char *address, ev_uint16_t port);
/**
* Associates an event base with the connection - can only be called
* on a freshly created connection object that has not been used yet.
*
* @deprecated XXXX Why?
*/
void evhttp_connection_set_base(struct evhttp_connection *evcon,
struct event_base *base);
/** Returns the request URI */
#define evhttp_request_uri evhttp_request_get_uri
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */

View File

@ -0,0 +1,152 @@
/*
* 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 EVENT2_HTTP_STRUCT_H_INCLUDED_
#define EVENT2_HTTP_STRUCT_H_INCLUDED_
/** @file event2/http_struct.h
Data structures for http. Using these structures may hurt forward
compatibility with later versions of Libevent: be careful!
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
/**
* the request structure that a server receives.
* WARNING: expect this structure to change. I will try to provide
* reasonable accessors.
*/
struct evhttp_request {
#if defined(TAILQ_ENTRY)
TAILQ_ENTRY(evhttp_request) next;
#else
struct {
struct evhttp_request *tqe_next;
struct evhttp_request **tqe_prev;
} next;
#endif
/* the connection object that this request belongs to */
struct evhttp_connection *evcon;
int flags;
/** The request obj owns the evhttp connection and needs to free it */
#define EVHTTP_REQ_OWN_CONNECTION 0x0001
/** Request was made via a proxy */
#define EVHTTP_PROXY_REQUEST 0x0002
/** The request object is owned by the user; the user must free it */
#define EVHTTP_USER_OWNED 0x0004
/** The request will be used again upstack; freeing must be deferred */
#define EVHTTP_REQ_DEFER_FREE 0x0008
/** The request should be freed upstack */
#define EVHTTP_REQ_NEEDS_FREE 0x0010
struct evkeyvalq *input_headers;
struct evkeyvalq *output_headers;
/* address of the remote host and the port connection came from */
char *remote_host;
ev_uint16_t remote_port;
/* cache of the hostname for evhttp_request_get_host */
char *host_cache;
enum evhttp_request_kind kind;
enum evhttp_cmd_type type;
size_t headers_size;
size_t body_size;
char *uri; /* uri after HTTP request was parsed */
struct evhttp_uri *uri_elems; /* uri elements */
char major; /* HTTP Major number */
char minor; /* HTTP Minor number */
int response_code; /* HTTP Response code */
char *response_code_line; /* Readable response */
struct evbuffer *input_buffer; /* read data */
ev_int64_t ntoread;
unsigned chunked:1, /* a chunked request */
userdone:1; /* the user has sent all data */
struct evbuffer *output_buffer; /* outgoing post or data */
/* Callback */
void (*cb)(struct evhttp_request *, void *);
void *cb_arg;
/*
* Chunked data callback - call for each completed chunk if
* specified. If not specified, all the data is delivered via
* the regular callback.
*/
void (*chunk_cb)(struct evhttp_request *, void *);
/*
* Callback added for forked-daapd so they can collect ICY
* (shoutcast) metadata from the http header. If return
* int is negative the connection will be closed.
*/
int (*header_cb)(struct evhttp_request *, void *);
/*
* Error callback - called when error is occured.
* @see evhttp_request_error for error types.
*
* @see evhttp_request_set_error_cb()
*/
void (*error_cb)(enum evhttp_request_error, void *);
/*
* Send complete callback - called when the request is actually
* sent and completed.
*/
void (*on_complete_cb)(struct evhttp_request *, void *);
void *on_complete_cb_arg;
};
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_HTTP_STRUCT_H_INCLUDED_ */

View File

@ -0,0 +1,80 @@
/*
* 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 EVENT2_KEYVALQ_STRUCT_H_INCLUDED_
#define EVENT2_KEYVALQ_STRUCT_H_INCLUDED_
#ifdef __cplusplus
extern "C" {
#endif
/* Fix so that people don't have to run with <sys/queue.h> */
/* XXXX This code is duplicated with event_struct.h */
#ifndef TAILQ_ENTRY
#define EVENT_DEFINED_TQENTRY_
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
#endif /* !TAILQ_ENTRY */
#ifndef TAILQ_HEAD
#define EVENT_DEFINED_TQHEAD_
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; \
struct type **tqh_last; \
}
#endif
/*
* Key-Value pairs. Can be used for HTTP headers but also for
* query argument parsing.
*/
struct evkeyval {
TAILQ_ENTRY(evkeyval) next;
char *key;
char *value;
};
TAILQ_HEAD (evkeyvalq, evkeyval);
/* XXXX This code is duplicated with event_struct.h */
#ifdef EVENT_DEFINED_TQENTRY_
#undef TAILQ_ENTRY
#endif
#ifdef EVENT_DEFINED_TQHEAD_
#undef TAILQ_HEAD
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,180 @@
/*
* 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 EVENT2_LISTENER_H_INCLUDED_
#define EVENT2_LISTENER_H_INCLUDED_
#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event.h>
struct sockaddr;
struct evconnlistener;
/**
A callback that we invoke when a listener has a new connection.
@param listener The evconnlistener
@param fd The new file descriptor
@param addr The source address of the connection
@param socklen The length of addr
@param user_arg the pointer passed to evconnlistener_new()
*/
typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);
/**
A callback that we invoke when a listener encounters a non-retriable error.
@param listener The evconnlistener
@param user_arg the pointer passed to evconnlistener_new()
*/
typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *);
/** Flag: Indicates that we should not make incoming sockets nonblocking
* before passing them to the callback. */
#define LEV_OPT_LEAVE_SOCKETS_BLOCKING (1u<<0)
/** Flag: Indicates that freeing the listener should close the underlying
* socket. */
#define LEV_OPT_CLOSE_ON_FREE (1u<<1)
/** Flag: Indicates that we should set the close-on-exec flag, if possible */
#define LEV_OPT_CLOSE_ON_EXEC (1u<<2)
/** Flag: Indicates that we should disable the timeout (if any) between when
* this socket is closed and when we can listen again on the same port. */
#define LEV_OPT_REUSEABLE (1u<<3)
/** Flag: Indicates that the listener should be locked so it's safe to use
* from multiple threadcs at once. */
#define LEV_OPT_THREADSAFE (1u<<4)
/** Flag: Indicates that the listener should be created in disabled
* state. Use evconnlistener_enable() to enable it later. */
#define LEV_OPT_DISABLED (1u<<5)
/** Flag: Indicates that the listener should defer accept() until data is
* available, if possible. Ignored on platforms that do not support this.
*
* This option can help performance for protocols where the client transmits
* immediately after connecting. Do not use this option if your protocol
* _doesn't_ start out with the client transmitting data, since in that case
* this option will sometimes cause the kernel to never tell you about the
* connection.
*
* This option is only supported by evconnlistener_new_bind(): it can't
* work with evconnlistener_new_fd(), since the listener needs to be told
* to use the option before it is actually bound.
*/
#define LEV_OPT_DEFERRED_ACCEPT (1u<<6)
/** Flag: Indicates that we ask to allow multiple servers (processes or
* threads) to bind to the same port if they each set the option.
*
* SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however
* SO_REUSEPORT does not imply SO_REUSEADDR.
*
* This is only available on Linux and kernel 3.9+
*/
#define LEV_OPT_REUSEABLE_PORT (1u<<7)
/**
Allocate a new evconnlistener object to listen for incoming TCP connections
on a given file descriptor.
@param base The event base to associate the listener with.
@param cb A callback to be invoked when a new connection arrives. If the
callback is NULL, the listener will be treated as disabled until the
callback is set.
@param ptr A user-supplied pointer to give to the callback.
@param flags Any number of LEV_OPT_* flags
@param backlog Passed to the listen() call to determine the length of the
acceptable connection backlog. Set to -1 for a reasonable default.
Set to 0 if the socket is already listening.
@param fd The file descriptor to listen on. It must be a nonblocking
file descriptor, and it should already be bound to an appropriate
port and address.
*/
EVENT2_EXPORT_SYMBOL
struct evconnlistener *evconnlistener_new(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
evutil_socket_t fd);
/**
Allocate a new evconnlistener object to listen for incoming TCP connections
on a given address.
@param base The event base to associate the listener with.
@param cb A callback to be invoked when a new connection arrives. If the
callback is NULL, the listener will be treated as disabled until the
callback is set.
@param ptr A user-supplied pointer to give to the callback.
@param flags Any number of LEV_OPT_* flags
@param backlog Passed to the listen() call to determine the length of the
acceptable connection backlog. Set to -1 for a reasonable default.
@param addr The address to listen for connections on.
@param socklen The length of the address.
*/
EVENT2_EXPORT_SYMBOL
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
const struct sockaddr *sa, int socklen);
/**
Disable and deallocate an evconnlistener.
*/
EVENT2_EXPORT_SYMBOL
void evconnlistener_free(struct evconnlistener *lev);
/**
Re-enable an evconnlistener that has been disabled.
*/
EVENT2_EXPORT_SYMBOL
int evconnlistener_enable(struct evconnlistener *lev);
/**
Stop listening for connections on an evconnlistener.
*/
EVENT2_EXPORT_SYMBOL
int evconnlistener_disable(struct evconnlistener *lev);
/** Return an evconnlistener's associated event_base. */
EVENT2_EXPORT_SYMBOL
struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
/** Return the socket that an evconnlistner is listening on. */
EVENT2_EXPORT_SYMBOL
evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
/** Change the callback on the listener to cb and its user_data to arg.
*/
EVENT2_EXPORT_SYMBOL
void evconnlistener_set_cb(struct evconnlistener *lev,
evconnlistener_cb cb, void *arg);
/** Set an evconnlistener's error callback. */
EVENT2_EXPORT_SYMBOL
void evconnlistener_set_error_cb(struct evconnlistener *lev,
evconnlistener_errorcb errorcb);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,596 @@
/*
* 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 EVENT2_RPC_H_INCLUDED_
#define EVENT2_RPC_H_INCLUDED_
#ifdef __cplusplus
extern "C" {
#endif
/** @file rpc.h
*
* This header files provides basic support for an RPC server and client.
*
* To support RPCs in a server, every supported RPC command needs to be
* defined and registered.
*
* EVRPC_HEADER(SendCommand, Request, Reply);
*
* SendCommand is the name of the RPC command.
* Request is the name of a structure generated by event_rpcgen.py.
* It contains all parameters relating to the SendCommand RPC. The
* server needs to fill in the Reply structure.
* Reply is the name of a structure generated by event_rpcgen.py. It
* contains the answer to the RPC.
*
* To register an RPC with an HTTP server, you need to first create an RPC
* base with:
*
* struct evrpc_base *base = evrpc_init(http);
*
* A specific RPC can then be registered with
*
* EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg);
*
* when the server receives an appropriately formatted RPC, the user callback
* is invoked. The callback needs to fill in the reply structure.
*
* void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
*
* To send the reply, call EVRPC_REQUEST_DONE(rpc);
*
* See the regression test for an example.
*/
/**
Determines if the member has been set in the message
@param msg the message to inspect
@param member the member variable to test for presences
@return 1 if it's present or 0 otherwise.
*/
#define EVTAG_HAS(msg, member) \
((msg)->member##_set == 1)
#ifndef EVENT2_RPC_COMPAT_H_INCLUDED_
/**
Assigns a value to the member in the message.
@param msg the message to which to assign a value
@param member the name of the member variable
@param value the value to assign
*/
#define EVTAG_ASSIGN(msg, member, value) \
(*(msg)->base->member##_assign)((msg), (value))
/**
Assigns a value to the member in the message.
@param msg the message to which to assign a value
@param member the name of the member variable
@param value the value to assign
@param len the length of the value
*/
#define EVTAG_ASSIGN_WITH_LEN(msg, member, value, len) \
(*(msg)->base->member##_assign)((msg), (value), (len))
/**
Returns the value for a member.
@param msg the message from which to get the value
@param member the name of the member variable
@param pvalue a pointer to the variable to hold the value
@return 0 on success, -1 otherwise.
*/
#define EVTAG_GET(msg, member, pvalue) \
(*(msg)->base->member##_get)((msg), (pvalue))
/**
Returns the value for a member.
@param msg the message from which to get the value
@param member the name of the member variable
@param pvalue a pointer to the variable to hold the value
@param plen a pointer to the length of the value
@return 0 on success, -1 otherwise.
*/
#define EVTAG_GET_WITH_LEN(msg, member, pvalue, plen) \
(*(msg)->base->member##_get)((msg), (pvalue), (plen))
#endif /* EVENT2_RPC_COMPAT_H_INCLUDED_ */
/**
Adds a value to an array.
*/
#define EVTAG_ARRAY_ADD_VALUE(msg, member, value) \
(*(msg)->base->member##_add)((msg), (value))
/**
Allocates a new entry in the array and returns it.
*/
#define EVTAG_ARRAY_ADD(msg, member) \
(*(msg)->base->member##_add)(msg)
/**
Gets a variable at the specified offset from the array.
*/
#define EVTAG_ARRAY_GET(msg, member, offset, pvalue) \
(*(msg)->base->member##_get)((msg), (offset), (pvalue))
/**
Returns the number of entries in the array.
*/
#define EVTAG_ARRAY_LEN(msg, member) ((msg)->member##_length)
struct evbuffer;
struct event_base;
struct evrpc_req_generic;
struct evrpc_request_wrapper;
struct evrpc;
/** The type of a specific RPC Message
*
* @param rpcname the name of the RPC message
*/
#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
struct evhttp_request;
struct evrpc_status;
struct evrpc_hook_meta;
/** Creates the definitions and prototypes for an RPC
*
* You need to use EVRPC_HEADER to create structures and function prototypes
* needed by the server and client implementation. The structures have to be
* defined in an .rpc file and converted to source code via event_rpcgen.py
*
* @param rpcname the name of the RPC
* @param reqstruct the name of the RPC request structure
* @param replystruct the name of the RPC reply structure
* @see EVRPC_GENERATE()
*/
#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
EVRPC_STRUCT(rpcname) { \
struct evrpc_hook_meta *hook_meta; \
struct reqstruct* request; \
struct rplystruct* reply; \
struct evrpc* rpc; \
struct evhttp_request* http_req; \
struct evbuffer* rpc_data; \
}; \
int evrpc_send_request_##rpcname(struct evrpc_pool *, \
struct reqstruct *, struct rplystruct *, \
void (*)(struct evrpc_status *, \
struct reqstruct *, struct rplystruct *, void *cbarg), \
void *);
struct evrpc_pool;
/** use EVRPC_GENERATE instead */
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);
/** Creates a context structure that contains rpc specific information.
*
* EVRPC_MAKE_CTX is used to populate a RPC specific context that
* contains information about marshaling the RPC data types.
*
* @param rpcname the name of the RPC
* @param reqstruct the name of the RPC request structure
* @param replystruct the name of the RPC reply structure
* @param pool the evrpc_pool over which to make the request
* @param request a pointer to the RPC request structure object
* @param reply a pointer to the RPC reply structure object
* @param cb the callback function to call when the RPC has completed
* @param cbarg the argument to supply to the callback
*/
#define EVRPC_MAKE_CTX(rpcname, reqstruct, rplystruct, \
pool, request, reply, cb, cbarg) \
evrpc_make_request_ctx(pool, request, reply, \
#rpcname, \
(void (*)(struct evbuffer *, void *))reqstruct##_marshal, \
(void (*)(void *))rplystruct##_clear, \
(int (*)(void *, struct evbuffer *))rplystruct##_unmarshal, \
(void (*)(struct evrpc_status *, void *, void *, void *))cb, \
cbarg)
/** Generates the code for receiving and sending an RPC message
*
* EVRPC_GENERATE is used to create the code corresponding to sending
* and receiving a particular RPC message
*
* @param rpcname the name of the RPC
* @param reqstruct the name of the RPC request structure
* @param replystruct the name of the RPC reply structure
* @see EVRPC_HEADER()
*/
#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
struct reqstruct *request, struct rplystruct *reply, \
void (*cb)(struct evrpc_status *, \
struct reqstruct *, struct rplystruct *, void *cbarg), \
void *cbarg) { \
return evrpc_send_request_generic(pool, request, reply, \
(void (*)(struct evrpc_status *, void *, void *, void *))cb, \
cbarg, \
#rpcname, \
(void (*)(struct evbuffer *, void *))reqstruct##_marshal, \
(void (*)(void *))rplystruct##_clear, \
(int (*)(void *, struct evbuffer *))rplystruct##_unmarshal); \
}
/** Provides access to the HTTP request object underlying an RPC
*
* Access to the underlying http object; can be used to look at headers or
* for getting the remote ip address
*
* @param rpc_req the rpc request structure provided to the server callback
* @return an struct evhttp_request object that can be inspected for
* HTTP headers or sender information.
*/
#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
/** completes the server response to an rpc request */
void evrpc_request_done(struct evrpc_req_generic *req);
/** accessors for request and reply */
void *evrpc_get_request(struct evrpc_req_generic *req);
void *evrpc_get_reply(struct evrpc_req_generic *req);
/** Creates the reply to an RPC request
*
* EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
* to have been filled in. The request and reply pointers become invalid
* after this call has finished.
*
* @param rpc_req the rpc request structure provided to the server callback
*/
#define EVRPC_REQUEST_DONE(rpc_req) do { \
struct evrpc_req_generic *req_ = (struct evrpc_req_generic *)(rpc_req); \
evrpc_request_done(req_); \
} while (0)
struct evrpc_base;
struct evhttp;
/* functions to start up the rpc system */
/** Creates a new rpc base from which RPC requests can be received
*
* @param server a pointer to an existing HTTP server
* @return a newly allocated evrpc_base struct
* @see evrpc_free()
*/
struct evrpc_base *evrpc_init(struct evhttp *server);
/**
* Frees the evrpc base
*
* For now, you are responsible for making sure that no rpcs are ongoing.
*
* @param base the evrpc_base object to be freed
* @see evrpc_init
*/
void evrpc_free(struct evrpc_base *base);
/** register RPCs with the HTTP Server
*
* registers a new RPC with the HTTP server, each RPC needs to have
* a unique name under which it can be identified.
*
* @param base the evrpc_base structure in which the RPC should be
* registered.
* @param name the name of the RPC
* @param request the name of the RPC request structure
* @param reply the name of the RPC reply structure
* @param callback the callback that should be invoked when the RPC
* is received. The callback has the following prototype
* void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
* @param cbarg an additional parameter that can be passed to the callback.
* The parameter can be used to carry around state.
*/
#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
evrpc_register_generic(base, #name, \
(void (*)(struct evrpc_req_generic *, void *))callback, cbarg, \
(void *(*)(void *))request##_new, NULL, \
(void (*)(void *))request##_free, \
(int (*)(void *, struct evbuffer *))request##_unmarshal, \
(void *(*)(void *))reply##_new, NULL, \
(void (*)(void *))reply##_free, \
(int (*)(void *))reply##_complete, \
(void (*)(struct evbuffer *, void *))reply##_marshal)
/**
Low level function for registering an RPC with a server.
Use EVRPC_REGISTER() instead.
@see EVRPC_REGISTER()
*/
int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
void (*)(struct evrpc_req_generic*, void *), void *);
/**
* Unregisters an already registered RPC
*
* @param base the evrpc_base object from which to unregister an RPC
* @param name the name of the rpc to unregister
* @return -1 on error or 0 when successful.
* @see EVRPC_REGISTER()
*/
#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc((base), #name)
int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
/*
* Client-side RPC support
*/
struct evhttp_connection;
struct evrpc_status;
/** launches an RPC and sends it to the server
*
* EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
*
* @param name the name of the RPC
* @param pool the evrpc_pool that contains the connection objects over which
* the request should be sent.
* @param request a pointer to the RPC request structure - it contains the
* data to be sent to the server.
* @param reply a pointer to the RPC reply structure. It is going to be filled
* if the request was answered successfully
* @param cb the callback to invoke when the RPC request has been answered
* @param cbarg an additional argument to be passed to the client
* @return 0 on success, -1 on failure
*/
#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \
evrpc_send_request_##name((pool), (request), (reply), (cb), (cbarg))
/**
Makes an RPC request based on the provided context.
This is a low-level function and should not be used directly
unless a custom context object is provided. Use EVRPC_MAKE_REQUEST()
instead.
@param ctx a context from EVRPC_MAKE_CTX()
@returns 0 on success, -1 otherwise.
@see EVRPC_MAKE_REQUEST(), EVRPC_MAKE_CTX()
*/
int evrpc_make_request(struct evrpc_request_wrapper *ctx);
/** creates an rpc connection pool
*
* a pool has a number of connections associated with it.
* rpc requests are always made via a pool.
*
* @param base a pointer to an struct event_based object; can be left NULL
* in singled-threaded applications
* @return a newly allocated struct evrpc_pool object
* @see evrpc_pool_free()
*/
struct evrpc_pool *evrpc_pool_new(struct event_base *base);
/** frees an rpc connection pool
*
* @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
* @see evrpc_pool_new()
*/
void evrpc_pool_free(struct evrpc_pool *pool);
/**
* Adds a connection over which rpc can be dispatched to the pool.
*
* The connection object must have been newly created.
*
* @param pool the pool to which to add the connection
* @param evcon the connection to add to the pool.
*/
void evrpc_pool_add_connection(struct evrpc_pool *pool,
struct evhttp_connection *evcon);
/**
* Removes a connection from the pool.
*
* The connection object must have been newly created.
*
* @param pool the pool from which to remove the connection
* @param evcon the connection to remove from the pool.
*/
void evrpc_pool_remove_connection(struct evrpc_pool *pool,
struct evhttp_connection *evcon);
/**
* Sets the timeout in secs after which a request has to complete. The
* RPC is completely aborted if it does not complete by then. Setting
* the timeout to 0 means that it never timeouts and can be used to
* implement callback type RPCs.
*
* Any connection already in the pool will be updated with the new
* timeout. Connections added to the pool after set_timeout has be
* called receive the pool timeout only if no timeout has been set
* for the connection itself.
*
* @param pool a pointer to a struct evrpc_pool object
* @param timeout_in_secs the number of seconds after which a request should
* timeout and a failure be returned to the callback.
*/
void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
/**
* Hooks for changing the input and output of RPCs; this can be used to
* implement compression, authentication, encryption, ...
*/
enum EVRPC_HOOK_TYPE {
EVRPC_INPUT, /**< apply the function to an input hook */
EVRPC_OUTPUT /**< apply the function to an output hook */
};
#ifndef _WIN32
/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it
* conflicts with platform headers. */
#define INPUT EVRPC_INPUT
/** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it
* conflicts with platform headers. */
#define OUTPUT EVRPC_OUTPUT
#endif
/**
* Return value from hook processing functions
*/
enum EVRPC_HOOK_RESULT {
EVRPC_TERMINATE = -1, /**< indicates the rpc should be terminated */
EVRPC_CONTINUE = 0, /**< continue processing the rpc */
EVRPC_PAUSE = 1 /**< pause processing request until resumed */
};
/** adds a processing hook to either an rpc base or rpc pool
*
* If a hook returns TERMINATE, the processing is aborted. On CONTINUE,
* the request is immediately processed after the hook returns. If the
* hook returns PAUSE, request processing stops until evrpc_resume_request()
* has been called.
*
* The add functions return handles that can be used for removing hooks.
*
* @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
* @param hook_type either INPUT or OUTPUT
* @param cb the callback to call when the hook is activated
* @param cb_arg an additional argument for the callback
* @return a handle to the hook so it can be removed later
* @see evrpc_remove_hook()
*/
void *evrpc_add_hook(void *vbase,
enum EVRPC_HOOK_TYPE hook_type,
int (*cb)(void *, struct evhttp_request *, struct evbuffer *, void *),
void *cb_arg);
/** removes a previously added hook
*
* @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
* @param hook_type either INPUT or OUTPUT
* @param handle a handle returned by evrpc_add_hook()
* @return 1 on success or 0 on failure
* @see evrpc_add_hook()
*/
int evrpc_remove_hook(void *vbase,
enum EVRPC_HOOK_TYPE hook_type,
void *handle);
/** resume a paused request
*
* @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
* @param ctx the context pointer provided to the original hook call
*/
int
evrpc_resume_request(void *vbase, void *ctx, enum EVRPC_HOOK_RESULT res);
/** adds meta data to request
*
* evrpc_hook_add_meta() allows hooks to add meta data to a request. for
* a client request, the meta data can be inserted by an outgoing request hook
* and retrieved by the incoming request hook.
*
* @param ctx the context provided to the hook call
* @param key a NUL-terminated c-string
* @param data the data to be associated with the key
* @param data_size the size of the data
*/
void evrpc_hook_add_meta(void *ctx, const char *key,
const void *data, size_t data_size);
/** retrieves meta data previously associated
*
* evrpc_hook_find_meta() can be used to retrieve meta data associated to a
* request by a previous hook.
* @param ctx the context provided to the hook call
* @param key a NUL-terminated c-string
* @param data pointer to a data pointer that will contain the retrieved data
* @param data_size pointer to the size of the data
* @return 0 on success or -1 on failure
*/
int evrpc_hook_find_meta(void *ctx, const char *key,
void **data, size_t *data_size);
/**
* returns the connection object associated with the request
*
* @param ctx the context provided to the hook call
* @return a pointer to the evhttp_connection object
*/
struct evhttp_connection *evrpc_hook_get_connection(void *ctx);
/**
Function for sending a generic RPC request.
Do not call this function directly, use EVRPC_MAKE_REQUEST() instead.
@see EVRPC_MAKE_REQUEST()
*/
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 *));
/**
Function for registering a generic RPC with the RPC base.
Do not call this function directly, use EVRPC_REGISTER() instead.
@see EVRPC_REGISTER()
*/
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 *));
/** accessors for obscure and undocumented functionality */
struct evrpc_pool* evrpc_request_get_pool(struct evrpc_request_wrapper *ctx);
void evrpc_request_set_pool(struct evrpc_request_wrapper *ctx,
struct evrpc_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);
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_RPC_H_INCLUDED_ */

View File

@ -0,0 +1,61 @@
/*
* 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 EVENT2_RPC_COMPAT_H_INCLUDED_
#define EVENT2_RPC_COMPAT_H_INCLUDED_
/** @file event2/rpc_compat.h
Deprecated versions of the functions in rpc.h: provided only for
backwards compatibility.
*/
#ifdef __cplusplus
extern "C" {
#endif
/** backwards compatible accessors that work only with gcc */
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#undef EVTAG_ASSIGN
#undef EVTAG_GET
#undef EVTAG_ADD
#define EVTAG_ASSIGN(msg, member, args...) \
(*(msg)->base->member##_assign)(msg, ## args)
#define EVTAG_GET(msg, member, args...) \
(*(msg)->base->member##_get)(msg, ## args)
#define EVTAG_ADD(msg, member, args...) \
(*(msg)->base->member##_add)(msg, ## args)
#endif
#define EVTAG_LEN(msg, member) ((msg)->member##_length)
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_EVENT_COMPAT_H_INCLUDED_ */

View File

@ -0,0 +1,100 @@
/*
* 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 EVENT2_RPC_STRUCT_H_INCLUDED_
#define EVENT2_RPC_STRUCT_H_INCLUDED_
#ifdef __cplusplus
extern "C" {
#endif
/** @file event2/rpc_struct.h
Structures used by rpc.h. Using these structures directly may harm
forward compatibility: be careful!
*/
/**
* provides information about the completed RPC request.
*/
struct evrpc_status {
#define EVRPC_STATUS_ERR_NONE 0
#define EVRPC_STATUS_ERR_TIMEOUT 1
#define EVRPC_STATUS_ERR_BADPAYLOAD 2
#define EVRPC_STATUS_ERR_UNSTARTED 3
#define EVRPC_STATUS_ERR_HOOKABORTED 4
int error;
/* for looking at headers or other information */
struct evhttp_request *http_req;
};
/* the structure below needs to be synchronized with evrpc_req_generic */
/* Encapsulates a request */
struct evrpc {
TAILQ_ENTRY(evrpc) next;
/* the URI at which the request handler lives */
const char* uri;
/* creates a new request structure */
void *(*request_new)(void *);
void *request_new_arg;
/* frees the request structure */
void (*request_free)(void *);
/* unmarshals the buffer into the proper request structure */
int (*request_unmarshal)(void *, struct evbuffer *);
/* creates a new reply structure */
void *(*reply_new)(void *);
void *reply_new_arg;
/* frees the reply structure */
void (*reply_free)(void *);
/* verifies that the reply is valid */
int (*reply_complete)(void *);
/* marshals the reply into a buffer */
void (*reply_marshal)(struct evbuffer*, void *);
/* the callback invoked for each received rpc */
void (*cb)(struct evrpc_req_generic *, void *);
void *cb_arg;
/* reference for further configuration */
struct evrpc_base *base;
};
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_RPC_STRUCT_H_INCLUDED_ */

View File

@ -0,0 +1,146 @@
/*
* 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 EVENT2_TAG_H_INCLUDED_
#define EVENT2_TAG_H_INCLUDED_
/** @file event2/tag.h
Helper functions for reading and writing tagged data onto buffers.
*/
#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* For int types. */
#include <event2/util.h>
struct evbuffer;
/*
* Marshaling tagged data - We assume that all tags are inserted in their
* numeric order - so that unknown tags will always be higher than the
* known ones - and we can just ignore the end of an event buffer.
*/
EVENT2_EXPORT_SYMBOL
void evtag_init(void);
/**
Unmarshals the header and returns the length of the payload
@param evbuf the buffer from which to unmarshal data
@param ptag a pointer in which the tag id is being stored
@returns -1 on failure or the number of bytes in the remaining payload.
*/
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_header(struct evbuffer *evbuf, ev_uint32_t *ptag);
EVENT2_EXPORT_SYMBOL
void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
ev_uint32_t len);
EVENT2_EXPORT_SYMBOL
void evtag_marshal_buffer(struct evbuffer *evbuf, ev_uint32_t tag,
struct evbuffer *data);
/**
Encode an integer and store it in an evbuffer.
We encode integers by nybbles; the first nibble contains the number
of significant nibbles - 1; this allows us to encode up to 64-bit
integers. This function is byte-order independent.
@param evbuf evbuffer to store the encoded number
@param number a 32-bit integer
*/
EVENT2_EXPORT_SYMBOL
void evtag_encode_int(struct evbuffer *evbuf, ev_uint32_t number);
EVENT2_EXPORT_SYMBOL
void evtag_encode_int64(struct evbuffer *evbuf, ev_uint64_t number);
EVENT2_EXPORT_SYMBOL
void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
ev_uint32_t integer);
EVENT2_EXPORT_SYMBOL
void evtag_marshal_int64(struct evbuffer *evbuf, ev_uint32_t tag,
ev_uint64_t integer);
EVENT2_EXPORT_SYMBOL
void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
const char *string);
EVENT2_EXPORT_SYMBOL
void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
struct timeval *tv);
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
struct evbuffer *dst);
EVENT2_EXPORT_SYMBOL
int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
EVENT2_EXPORT_SYMBOL
int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
EVENT2_EXPORT_SYMBOL
int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
EVENT2_EXPORT_SYMBOL
int evtag_consume(struct evbuffer *evbuf);
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
ev_uint32_t *pinteger);
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_int64(struct evbuffer *evbuf, ev_uint32_t need_tag,
ev_uint64_t *pinteger);
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
void *data, size_t len);
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
char **pstring);
EVENT2_EXPORT_SYMBOL
int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
struct timeval *ptv);
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_TAG_H_INCLUDED_ */

View File

@ -0,0 +1,49 @@
/*
* 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 EVENT2_TAG_COMPAT_H_INCLUDED_
#define EVENT2_TAG_COMPAT_H_INCLUDED_
/** @file event2/tag_compat.h
Obsolete/deprecated functions from tag.h; provided only for backwards
compatibility.
*/
/**
@name Misnamed functions
@deprecated These macros are deprecated because their names don't follow
Libevent's naming conventions. Use evtag_encode_int and
evtag_encode_int64 instead.
@{
*/
#define encode_int(evbuf, number) evtag_encode_int((evbuf), (number))
#define encode_int64(evbuf, number) evtag_encode_int64((evbuf), (number))
/**@}*/
#endif /* EVENT2_TAG_H_INCLUDED_ */

View File

@ -0,0 +1,253 @@
/*
* 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 EVENT2_THREAD_H_INCLUDED_
#define EVENT2_THREAD_H_INCLUDED_
/** @file event2/thread.h
Functions for multi-threaded applications using Libevent.
When using a multi-threaded application in which multiple threads
add and delete events from a single event base, Libevent needs to
lock its data structures.
Like the memory-management function hooks, all of the threading functions
_must_ be set up before an event_base is created if you want the base to
use them.
Most programs will either be using Windows threads or Posix threads. You
can configure Libevent to use one of these event_use_windows_threads() or
event_use_pthreads() respectively. If you're using another threading
library, you'll need to configure threading functions manually using
evthread_set_lock_callbacks() and evthread_set_condition_callbacks().
*/
#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
/**
@name Flags passed to lock functions
@{
*/
/** A flag passed to a locking callback when the lock was allocated as a
* read-write lock, and we want to acquire or release the lock for writing. */
#define EVTHREAD_WRITE 0x04
/** A flag passed to a locking callback when the lock was allocated as a
* read-write lock, and we want to acquire or release the lock for reading. */
#define EVTHREAD_READ 0x08
/** A flag passed to a locking callback when we don't want to block waiting
* for the lock; if we can't get the lock immediately, we will instead
* return nonzero from the locking callback. */
#define EVTHREAD_TRY 0x10
/**@}*/
#if !defined(EVENT__DISABLE_THREAD_SUPPORT) || defined(EVENT_IN_DOXYGEN_)
#define EVTHREAD_LOCK_API_VERSION 1
/**
@name Types of locks
@{*/
/** A recursive lock is one that can be acquired multiple times at once by the
* same thread. No other process can allocate the lock until the thread that
* has been holding it has unlocked it as many times as it locked it. */
#define EVTHREAD_LOCKTYPE_RECURSIVE 1
/* A read-write lock is one that allows multiple simultaneous readers, but
* where any one writer excludes all other writers and readers. */
#define EVTHREAD_LOCKTYPE_READWRITE 2
/**@}*/
/** This structure describes the interface a threading library uses for
* locking. It's used to tell evthread_set_lock_callbacks() how to use
* locking on this platform.
*/
struct evthread_lock_callbacks {
/** The current version of the locking API. Set this to
* EVTHREAD_LOCK_API_VERSION */
int lock_api_version;
/** Which kinds of locks does this version of the locking API
* support? A bitfield of EVTHREAD_LOCKTYPE_RECURSIVE and
* EVTHREAD_LOCKTYPE_READWRITE.
*
* (Note that RECURSIVE locks are currently mandatory, and
* READWRITE locks are not currently used.)
**/
unsigned supported_locktypes;
/** Function to allocate and initialize new lock of type 'locktype'.
* Returns NULL on failure. */
void *(*alloc)(unsigned locktype);
/** Funtion to release all storage held in 'lock', which was created
* with type 'locktype'. */
void (*free)(void *lock, unsigned locktype);
/** Acquire an already-allocated lock at 'lock' with mode 'mode'.
* Returns 0 on success, and nonzero on failure. */
int (*lock)(unsigned mode, void *lock);
/** Release a lock at 'lock' using mode 'mode'. Returns 0 on success,
* and nonzero on failure. */
int (*unlock)(unsigned mode, void *lock);
};
/** Sets a group of functions that Libevent should use for locking.
* For full information on the required callback API, see the
* documentation for the individual members of evthread_lock_callbacks.
*
* Note that if you're using Windows or the Pthreads threading library, you
* probably shouldn't call this function; instead, use
* evthread_use_windows_threads() or evthread_use_posix_threads() if you can.
*/
EVENT2_EXPORT_SYMBOL
int evthread_set_lock_callbacks(const struct evthread_lock_callbacks *);
#define EVTHREAD_CONDITION_API_VERSION 1
struct timeval;
/** This structure describes the interface a threading library uses for
* condition variables. It's used to tell evthread_set_condition_callbacks
* how to use locking on this platform.
*/
struct evthread_condition_callbacks {
/** The current version of the conditions API. Set this to
* EVTHREAD_CONDITION_API_VERSION */
int condition_api_version;
/** Function to allocate and initialize a new condition variable.
* Returns the condition variable on success, and NULL on failure.
* The 'condtype' argument will be 0 with this API version.
*/
void *(*alloc_condition)(unsigned condtype);
/** Function to free a condition variable. */
void (*free_condition)(void *cond);
/** Function to signal a condition variable. If 'broadcast' is 1, all
* threads waiting on 'cond' should be woken; otherwise, only on one
* thread is worken. Should return 0 on success, -1 on failure.
* This function will only be called while holding the associated
* lock for the condition.
*/
int (*signal_condition)(void *cond, int broadcast);
/** Function to wait for a condition variable. The lock 'lock'
* will be held when this function is called; should be released
* while waiting for the condition to be come signalled, and
* should be held again when this function returns.
* If timeout is provided, it is interval of seconds to wait for
* the event to become signalled; if it is NULL, the function
* should wait indefinitely.
*
* The function should return -1 on error; 0 if the condition
* was signalled, or 1 on a timeout. */
int (*wait_condition)(void *cond, void *lock,
const struct timeval *timeout);
};
/** Sets a group of functions that Libevent should use for condition variables.
* For full information on the required callback API, see the
* documentation for the individual members of evthread_condition_callbacks.
*
* Note that if you're using Windows or the Pthreads threading library, you
* probably shouldn't call this function; instead, use
* evthread_use_windows_threads() or evthread_use_pthreads() if you can.
*/
EVENT2_EXPORT_SYMBOL
int evthread_set_condition_callbacks(
const struct evthread_condition_callbacks *);
/**
Sets the function for determining the thread id.
@param base the event base for which to set the id function
@param id_fn the identify function Libevent should invoke to
determine the identity of a thread.
*/
EVENT2_EXPORT_SYMBOL
void evthread_set_id_callback(
unsigned long (*id_fn)(void));
#if (defined(_WIN32) && !defined(EVENT__DISABLE_THREAD_SUPPORT)) || defined(EVENT_IN_DOXYGEN_)
/** Sets up Libevent for use with Windows builtin locking and thread ID
functions. Unavailable if Libevent is not built for Windows.
@return 0 on success, -1 on failure. */
EVENT2_EXPORT_SYMBOL
int evthread_use_windows_threads(void);
/**
Defined if Libevent was built with support for evthread_use_windows_threads()
*/
#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 1
#endif
#if defined(EVENT__HAVE_PTHREADS) || defined(EVENT_IN_DOXYGEN_)
/** Sets up Libevent for use with Pthreads locking and thread ID functions.
Unavailable if Libevent is not build for use with pthreads. Requires
libraries to link against Libevent_pthreads as well as Libevent.
@return 0 on success, -1 on failure. */
EVENT2_EXPORT_SYMBOL
int evthread_use_pthreads(void);
/** Defined if Libevent was built with support for evthread_use_pthreads() */
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1
#endif
/** Enable debugging wrappers around the current lock callbacks. If Libevent
* makes one of several common locking errors, exit with an assertion failure.
*
* If you're going to call this function, you must do so before any locks are
* allocated.
**/
EVENT2_EXPORT_SYMBOL
void evthread_enable_lock_debugging(void);
/* Old (misspelled) version: This is deprecated; use
* evthread_enable_log_debugging instead. */
EVENT2_EXPORT_SYMBOL
void evthread_enable_lock_debuging(void);
#endif /* EVENT__DISABLE_THREAD_SUPPORT */
struct event_base;
/** Make sure it's safe to tell an event base to wake up from another thread
or a signal handler.
You shouldn't need to call this by hand; configuring the base with thread
support should be necessary and sufficient.
@return 0 on success, -1 on failure.
*/
EVENT2_EXPORT_SYMBOL
int evthread_make_base_notifiable(struct event_base *base);
#ifdef __cplusplus
}
#endif
#endif /* EVENT2_THREAD_H_INCLUDED_ */

View File

@ -0,0 +1,866 @@
/*
* 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 EVENT2_UTIL_H_INCLUDED_
#define EVENT2_UTIL_H_INCLUDED_
/** @file event2/util.h
Common convenience functions for cross-platform portability and
related socket manipulations.
*/
#include <event2/visibility.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <event2/event-config.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef EVENT__HAVE_STDINT_H
#include <stdint.h>
#elif defined(EVENT__HAVE_INTTYPES_H)
#include <inttypes.h>
#endif
#ifdef EVENT__HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef EVENT__HAVE_STDDEF_H
#include <stddef.h>
#endif
#ifdef _MSC_VER
#include <BaseTsd.h>
#endif
#include <stdarg.h>
#ifdef EVENT__HAVE_NETDB_H
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <netdb.h>
#endif
#ifdef _WIN32
#include <winsock2.h>
#ifdef EVENT__HAVE_GETADDRINFO
/* for EAI_* definitions. */
#include <ws2tcpip.h>
#endif
#else
#ifdef EVENT__HAVE_ERRNO_H
#include <errno.h>
#endif
#include <sys/socket.h>
#endif
#include <time.h>
/* Some openbsd autoconf versions get the name of this macro wrong. */
#if defined(EVENT__SIZEOF_VOID__) && !defined(EVENT__SIZEOF_VOID_P)
#define EVENT__SIZEOF_VOID_P EVENT__SIZEOF_VOID__
#endif
/**
* @name Standard integer types.
*
* Integer type definitions for types that are supposed to be defined in the
* C99-specified stdint.h. Shamefully, some platforms do not include
* stdint.h, so we need to replace it. (If you are on a platform like this,
* your C headers are now over 10 years out of date. You should bug them to
* do something about this.)
*
* We define:
*
* <dl>
* <dt>ev_uint64_t, ev_uint32_t, ev_uint16_t, ev_uint8_t</dt>
* <dd>unsigned integer types of exactly 64, 32, 16, and 8 bits
* respectively.</dd>
* <dt>ev_int64_t, ev_int32_t, ev_int16_t, ev_int8_t</dt>
* <dd>signed integer types of exactly 64, 32, 16, and 8 bits
* respectively.</dd>
* <dt>ev_uintptr_t, ev_intptr_t</dt>
* <dd>unsigned/signed integers large enough
* to hold a pointer without loss of bits.</dd>
* <dt>ev_ssize_t</dt>
* <dd>A signed type of the same size as size_t</dd>
* <dt>ev_off_t</dt>
* <dd>A signed type typically used to represent offsets within a
* (potentially large) file</dd>
*
* @{
*/
#ifdef EVENT__HAVE_UINT64_T
#define ev_uint64_t uint64_t
#define ev_int64_t int64_t
#elif defined(_WIN32)
#define ev_uint64_t unsigned __int64
#define ev_int64_t signed __int64
#elif EVENT__SIZEOF_LONG_LONG == 8
#define ev_uint64_t unsigned long long
#define ev_int64_t long long
#elif EVENT__SIZEOF_LONG == 8
#define ev_uint64_t unsigned long
#define ev_int64_t long
#elif defined(EVENT_IN_DOXYGEN_)
#define ev_uint64_t ...
#define ev_int64_t ...
#else
#error "No way to define ev_uint64_t"
#endif
#ifdef EVENT__HAVE_UINT32_T
#define ev_uint32_t uint32_t
#define ev_int32_t int32_t
#elif defined(_WIN32)
#define ev_uint32_t unsigned int
#define ev_int32_t signed int
#elif EVENT__SIZEOF_LONG == 4
#define ev_uint32_t unsigned long
#define ev_int32_t signed long
#elif EVENT__SIZEOF_INT == 4
#define ev_uint32_t unsigned int
#define ev_int32_t signed int
#elif defined(EVENT_IN_DOXYGEN_)
#define ev_uint32_t ...
#define ev_int32_t ...
#else
#error "No way to define ev_uint32_t"
#endif
#ifdef EVENT__HAVE_UINT16_T
#define ev_uint16_t uint16_t
#define ev_int16_t int16_t
#elif defined(_WIN32)
#define ev_uint16_t unsigned short
#define ev_int16_t signed short
#elif EVENT__SIZEOF_INT == 2
#define ev_uint16_t unsigned int
#define ev_int16_t signed int
#elif EVENT__SIZEOF_SHORT == 2
#define ev_uint16_t unsigned short
#define ev_int16_t signed short
#elif defined(EVENT_IN_DOXYGEN_)
#define ev_uint16_t ...
#define ev_int16_t ...
#else
#error "No way to define ev_uint16_t"
#endif
#ifdef EVENT__HAVE_UINT8_T
#define ev_uint8_t uint8_t
#define ev_int8_t int8_t
#elif defined(EVENT_IN_DOXYGEN_)
#define ev_uint8_t ...
#define ev_int8_t ...
#else
#define ev_uint8_t unsigned char
#define ev_int8_t signed char
#endif
#ifdef EVENT__HAVE_UINTPTR_T
#define ev_uintptr_t uintptr_t
#define ev_intptr_t intptr_t
#elif EVENT__SIZEOF_VOID_P <= 4
#define ev_uintptr_t ev_uint32_t
#define ev_intptr_t ev_int32_t
#elif EVENT__SIZEOF_VOID_P <= 8
#define ev_uintptr_t ev_uint64_t
#define ev_intptr_t ev_int64_t
#elif defined(EVENT_IN_DOXYGEN_)
#define ev_uintptr_t ...
#define ev_intptr_t ...
#else
#error "No way to define ev_uintptr_t"
#endif
#ifdef EVENT__ssize_t
#define ev_ssize_t EVENT__ssize_t
#else
#define ev_ssize_t ssize_t
#endif
/* Note that we define ev_off_t based on the compile-time size of off_t that
* we used to build Libevent, and not based on the current size of off_t.
* (For example, we don't define ev_off_t to off_t.). We do this because
* some systems let you build your software with different off_t sizes
* at runtime, and so putting in any dependency on off_t would risk API
* mismatch.
*/
#ifdef _WIN32
#define ev_off_t ev_int64_t
#elif EVENT__SIZEOF_OFF_T == 8
#define ev_off_t ev_int64_t
#elif EVENT__SIZEOF_OFF_T == 4
#define ev_off_t ev_int32_t
#elif defined(EVENT_IN_DOXYGEN_)
#define ev_off_t ...
#else
#define ev_off_t off_t
#endif
/**@}*/
/* Limits for integer types.
We're making two assumptions here:
- The compiler does constant folding properly.
- The platform does signed arithmetic in two's complement.
*/
/**
@name Limits for integer types
These macros hold the largest or smallest values possible for the
ev_[u]int*_t types.
@{
*/
#ifndef EVENT__HAVE_STDINT_H
#define EV_UINT64_MAX ((((ev_uint64_t)0xffffffffUL) << 32) | 0xffffffffUL)
#define EV_INT64_MAX ((((ev_int64_t) 0x7fffffffL) << 32) | 0xffffffffL)
#define EV_INT64_MIN ((-EV_INT64_MAX) - 1)
#define EV_UINT32_MAX ((ev_uint32_t)0xffffffffUL)
#define EV_INT32_MAX ((ev_int32_t) 0x7fffffffL)
#define EV_INT32_MIN ((-EV_INT32_MAX) - 1)
#define EV_UINT16_MAX ((ev_uint16_t)0xffffUL)
#define EV_INT16_MAX ((ev_int16_t) 0x7fffL)
#define EV_INT16_MIN ((-EV_INT16_MAX) - 1)
#define EV_UINT8_MAX 255
#define EV_INT8_MAX 127
#define EV_INT8_MIN ((-EV_INT8_MAX) - 1)
#else
#define EV_UINT64_MAX UINT64_MAX
#define EV_INT64_MAX INT64_MAX
#define EV_INT64_MIN INT64_MIN
#define EV_UINT32_MAX UINT32_MAX
#define EV_INT32_MAX INT32_MAX
#define EV_INT32_MIN INT32_MIN
#define EV_UINT16_MAX UINT16_MAX
#define EV_INT16_MAX INT16_MAX
#define EV_UINT8_MAX UINT8_MAX
#define EV_INT8_MAX INT8_MAX
#define EV_INT8_MIN INT8_MIN
/** @} */
#endif
/**
@name Limits for SIZE_T and SSIZE_T
@{
*/
#if EVENT__SIZEOF_SIZE_T == 8
#define EV_SIZE_MAX EV_UINT64_MAX
#define EV_SSIZE_MAX EV_INT64_MAX
#elif EVENT__SIZEOF_SIZE_T == 4
#define EV_SIZE_MAX EV_UINT32_MAX
#define EV_SSIZE_MAX EV_INT32_MAX
#elif defined(EVENT_IN_DOXYGEN_)
#define EV_SIZE_MAX ...
#define EV_SSIZE_MAX ...
#else
#error "No way to define SIZE_MAX"
#endif
#define EV_SSIZE_MIN ((-EV_SSIZE_MAX) - 1)
/**@}*/
#ifdef _WIN32
#define ev_socklen_t int
#elif defined(EVENT__socklen_t)
#define ev_socklen_t EVENT__socklen_t
#else
#define ev_socklen_t socklen_t
#endif
#ifdef EVENT__HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
#if !defined(EVENT__HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) \
&& !defined(ss_family)
#define ss_family __ss_family
#endif
#endif
/**
* A type wide enough to hold the output of "socket()" or "accept()". On
* Windows, this is an intptr_t; elsewhere, it is an int. */
#ifdef _WIN32
#define evutil_socket_t intptr_t
#else
#define evutil_socket_t int
#endif
/**
* Structure to hold information about a monotonic timer
*
* Use this with evutil_configure_monotonic_time() and
* evutil_gettime_monotonic().
*
* This is an opaque structure; you can allocate one using
* evutil_monotonic_timer_new().
*
* @see evutil_monotonic_timer_new(), evutil_monotonic_timer_free(),
* evutil_configure_monotonic_time(), evutil_gettime_monotonic()
*/
struct evutil_monotonic_timer
#ifdef EVENT_IN_DOXYGEN_
{/*Empty body so that doxygen will generate documentation here.*/}
#endif
;
#define EV_MONOT_PRECISE 1
#define EV_MONOT_FALLBACK 2
/** Format a date string using RFC 1123 format (used in HTTP).
* If `tm` is NULL, current system's time will be used.
* The number of characters written will be returned.
* One should check if the return value is smaller than `datelen` to check if
* the result is truncated or not.
*/
EVENT2_EXPORT_SYMBOL int
evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm);
/** Allocate a new struct evutil_monotonic_timer for use with the
* evutil_configure_monotonic_time() and evutil_gettime_monotonic()
* functions. You must configure the timer with
* evutil_configure_monotonic_time() before using it.
*/
EVENT2_EXPORT_SYMBOL
struct evutil_monotonic_timer * evutil_monotonic_timer_new(void);
/** Free a struct evutil_monotonic_timer that was allocated using
* evutil_monotonic_timer_new().
*/
EVENT2_EXPORT_SYMBOL
void evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer);
/** Set up a struct evutil_monotonic_timer; flags can include
* EV_MONOT_PRECISE and EV_MONOT_FALLBACK.
*/
EVENT2_EXPORT_SYMBOL
int evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer,
int flags);
/** Query the current monotonic time from a struct evutil_monotonic_timer
* previously configured with evutil_configure_monotonic_time(). Monotonic
* time is guaranteed never to run in reverse, but is not necessarily epoch-
* based, or relative to any other definite point. Use it to make reliable
* measurements of elapsed time between events even when the system time
* may be changed.
*
* It is not safe to use this funtion on the same timer from multiple
* threads.
*/
EVENT2_EXPORT_SYMBOL
int evutil_gettime_monotonic(struct evutil_monotonic_timer *timer,
struct timeval *tp);
/** Create two new sockets that are connected to each other.
On Unix, this simply calls socketpair(). On Windows, it uses the
loopback network interface on 127.0.0.1, and only
AF_INET,SOCK_STREAM are supported.
(This may fail on some Windows hosts where firewall software has cleverly
decided to keep 127.0.0.1 from talking to itself.)
Parameters and return values are as for socketpair()
*/
EVENT2_EXPORT_SYMBOL
int evutil_socketpair(int d, int type, int protocol, evutil_socket_t sv[2]);
/** Do platform-specific operations as needed to make a socket nonblocking.
@param sock The socket to make nonblocking
@return 0 on success, -1 on failure
*/
EVENT2_EXPORT_SYMBOL
int evutil_make_socket_nonblocking(evutil_socket_t sock);
/** Do platform-specific operations to make a listener socket reusable.
Specifically, we want to make sure that another program will be able
to bind this address right after we've closed the listener.
This differs from Windows's interpretation of "reusable", which
allows multiple listeners to bind the same address at the same time.
@param sock The socket to make reusable
@return 0 on success, -1 on failure
*/
EVENT2_EXPORT_SYMBOL
int evutil_make_listen_socket_reuseable(evutil_socket_t sock);
/** Do platform-specific operations to make a listener port reusable.
Specifically, we want to make sure that multiple programs which also
set the same socket option will be able to bind, listen at the same time.
This is a feature available only to Linux 3.9+
@param sock The socket to make reusable
@return 0 on success, -1 on failure
*/
EVENT2_EXPORT_SYMBOL
int evutil_make_listen_socket_reuseable_port(evutil_socket_t sock);
/** Do platform-specific operations as needed to close a socket upon a
successful execution of one of the exec*() functions.
@param sock The socket to be closed
@return 0 on success, -1 on failure
*/
EVENT2_EXPORT_SYMBOL
int evutil_make_socket_closeonexec(evutil_socket_t sock);
/** Do the platform-specific call needed to close a socket returned from
socket() or accept().
@param sock The socket to be closed
@return 0 on success, -1 on failure
*/
EVENT2_EXPORT_SYMBOL
int evutil_closesocket(evutil_socket_t sock);
#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)
/** Do platform-specific operations, if possible, to make a tcp listener
* socket defer accept()s until there is data to read.
*
* Not all platforms support this. You don't want to do this for every
* listener socket: only the ones that implement a protocol where the
* client transmits before the server needs to respond.
*
* @param sock The listening socket to to make deferred
* @return 0 on success (whether the operation is supported or not),
* -1 on failure
*/
EVENT2_EXPORT_SYMBOL
int evutil_make_tcp_listen_socket_deferred(evutil_socket_t sock);
#ifdef _WIN32
/** Return the most recent socket error. Not idempotent on all platforms. */
#define EVUTIL_SOCKET_ERROR() WSAGetLastError()
/** Replace the most recent socket error with errcode */
#define EVUTIL_SET_SOCKET_ERROR(errcode) \
do { WSASetLastError(errcode); } while (0)
/** Return the most recent socket error to occur on sock. */
EVENT2_EXPORT_SYMBOL
int evutil_socket_geterror(evutil_socket_t sock);
/** Convert a socket error to a string. */
EVENT2_EXPORT_SYMBOL
const char *evutil_socket_error_to_string(int errcode);
#elif defined(EVENT_IN_DOXYGEN_)
/**
@name Socket error functions
These functions are needed for making programs compatible between
Windows and Unix-like platforms.
You see, Winsock handles socket errors differently from the rest of
the world. Elsewhere, a socket error is like any other error and is
stored in errno. But winsock functions require you to retrieve the
error with a special function, and don't let you use strerror for
the error codes. And handling EWOULDBLOCK is ... different.
@{
*/
/** Return the most recent socket error. Not idempotent on all platforms. */
#define EVUTIL_SOCKET_ERROR() ...
/** Replace the most recent socket error with errcode */
#define EVUTIL_SET_SOCKET_ERROR(errcode) ...
/** Return the most recent socket error to occur on sock. */
#define evutil_socket_geterror(sock) ...
/** Convert a socket error to a string. */
#define evutil_socket_error_to_string(errcode) ...
/**@}*/
#else
#define EVUTIL_SOCKET_ERROR() (errno)
#define EVUTIL_SET_SOCKET_ERROR(errcode) \
do { errno = (errcode); } while (0)
#define evutil_socket_geterror(sock) (errno)
#define evutil_socket_error_to_string(errcode) (strerror(errcode))
#endif
/**
* @name Manipulation macros for struct timeval.
*
* We define replacements
* for timeradd, timersub, timerclear, timercmp, and timerisset.
*
* @{
*/
#ifdef EVENT__HAVE_TIMERADD
#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp))
#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp))
#else
#define evutil_timeradd(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
if ((vvp)->tv_usec >= 1000000) { \
(vvp)->tv_sec++; \
(vvp)->tv_usec -= 1000000; \
} \
} while (0)
#define evutil_timersub(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (0)
#endif /* !EVENT__HAVE_TIMERADD */
#ifdef EVENT__HAVE_TIMERCLEAR
#define evutil_timerclear(tvp) timerclear(tvp)
#else
#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
#endif
/**@}*/
/** Return true iff the tvp is related to uvp according to the relational
* operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */
#define evutil_timercmp(tvp, uvp, cmp) \
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
((tvp)->tv_sec cmp (uvp)->tv_sec))
#ifdef EVENT__HAVE_TIMERISSET
#define evutil_timerisset(tvp) timerisset(tvp)
#else
#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
#endif
/** Replacement for offsetof on platforms that don't define it. */
#ifdef offsetof
#define evutil_offsetof(type, field) offsetof(type, field)
#else
#define evutil_offsetof(type, field) ((off_t)(&((type *)0)->field))
#endif
/* big-int related functions */
/** Parse a 64-bit value from a string. Arguments are as for strtol. */
EVENT2_EXPORT_SYMBOL
ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
/** Replacement for gettimeofday on platforms that lack it. */
#ifdef EVENT__HAVE_GETTIMEOFDAY
#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
#else
struct timezone;
EVENT2_EXPORT_SYMBOL
int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
#endif
/** Replacement for snprintf to get consistent behavior on platforms for
which the return value of snprintf does not conform to C99.
*/
EVENT2_EXPORT_SYMBOL
int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
#ifdef __GNUC__
__attribute__((format(printf, 3, 4)))
#endif
;
/** Replacement for vsnprintf to get consistent behavior on platforms for
which the return value of snprintf does not conform to C99.
*/
EVENT2_EXPORT_SYMBOL
int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
#ifdef __GNUC__
__attribute__((format(printf, 3, 0)))
#endif
;
/** Replacement for inet_ntop for platforms which lack it. */
EVENT2_EXPORT_SYMBOL
const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len);
/** Replacement for inet_pton for platforms which lack it. */
EVENT2_EXPORT_SYMBOL
int evutil_inet_pton(int af, const char *src, void *dst);
struct sockaddr;
/** Parse an IPv4 or IPv6 address, with optional port, from a string.
Recognized formats are:
- [IPv6Address]:port
- [IPv6Address]
- IPv6Address
- IPv4Address:port
- IPv4Address
If no port is specified, the port in the output is set to 0.
@param str The string to parse.
@param out A struct sockaddr to hold the result. This should probably be
a struct sockaddr_storage.
@param outlen A pointer to the number of bytes that that 'out' can safely
hold. Set to the number of bytes used in 'out' on success.
@return -1 if the address is not well-formed, if the port is out of range,
or if out is not large enough to hold the result. Otherwise returns
0 on success.
*/
EVENT2_EXPORT_SYMBOL
int evutil_parse_sockaddr_port(const char *str, struct sockaddr *out, int *outlen);
/** Compare two sockaddrs; return 0 if they are equal, or less than 0 if sa1
* preceeds sa2, or greater than 0 if sa1 follows sa2. If include_port is
* true, consider the port as well as the address. Only implemented for
* AF_INET and AF_INET6 addresses. The ordering is not guaranteed to remain
* the same between Libevent versions. */
EVENT2_EXPORT_SYMBOL
int evutil_sockaddr_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2,
int include_port);
/** As strcasecmp, but always compares the characters in locale-independent
ASCII. That's useful if you're handling data in ASCII-based protocols.
*/
EVENT2_EXPORT_SYMBOL
int evutil_ascii_strcasecmp(const char *str1, const char *str2);
/** As strncasecmp, but always compares the characters in locale-independent
ASCII. That's useful if you're handling data in ASCII-based protocols.
*/
EVENT2_EXPORT_SYMBOL
int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n);
/* Here we define evutil_addrinfo to the native addrinfo type, or redefine it
* if this system has no getaddrinfo(). */
#ifdef EVENT__HAVE_STRUCT_ADDRINFO
#define evutil_addrinfo addrinfo
#else
/** A definition of struct addrinfo for systems that lack it.
(This is just an alias for struct addrinfo if the system defines
struct addrinfo.)
*/
struct evutil_addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for nodename */
struct sockaddr *ai_addr; /* binary address */
struct evutil_addrinfo *ai_next; /* next structure in linked list */
};
#endif
/** @name evutil_getaddrinfo() error codes
These values are possible error codes for evutil_getaddrinfo() and
related functions.
@{
*/
#if defined(EAI_ADDRFAMILY) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_ADDRFAMILY EAI_ADDRFAMILY
#else
#define EVUTIL_EAI_ADDRFAMILY -901
#endif
#if defined(EAI_AGAIN) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_AGAIN EAI_AGAIN
#else
#define EVUTIL_EAI_AGAIN -902
#endif
#if defined(EAI_BADFLAGS) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_BADFLAGS EAI_BADFLAGS
#else
#define EVUTIL_EAI_BADFLAGS -903
#endif
#if defined(EAI_FAIL) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_FAIL EAI_FAIL
#else
#define EVUTIL_EAI_FAIL -904
#endif
#if defined(EAI_FAMILY) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_FAMILY EAI_FAMILY
#else
#define EVUTIL_EAI_FAMILY -905
#endif
#if defined(EAI_MEMORY) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_MEMORY EAI_MEMORY
#else
#define EVUTIL_EAI_MEMORY -906
#endif
/* This test is a bit complicated, since some MS SDKs decide to
* remove NODATA or redefine it to be the same as NONAME, in a
* fun interpretation of RFC 2553 and RFC 3493. */
#if defined(EAI_NODATA) && defined(EVENT__HAVE_GETADDRINFO) && (!defined(EAI_NONAME) || EAI_NODATA != EAI_NONAME)
#define EVUTIL_EAI_NODATA EAI_NODATA
#else
#define EVUTIL_EAI_NODATA -907
#endif
#if defined(EAI_NONAME) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_NONAME EAI_NONAME
#else
#define EVUTIL_EAI_NONAME -908
#endif
#if defined(EAI_SERVICE) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_SERVICE EAI_SERVICE
#else
#define EVUTIL_EAI_SERVICE -909
#endif
#if defined(EAI_SOCKTYPE) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_SOCKTYPE EAI_SOCKTYPE
#else
#define EVUTIL_EAI_SOCKTYPE -910
#endif
#if defined(EAI_SYSTEM) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_EAI_SYSTEM EAI_SYSTEM
#else
#define EVUTIL_EAI_SYSTEM -911
#endif
#define EVUTIL_EAI_CANCEL -90001
#if defined(AI_PASSIVE) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_PASSIVE AI_PASSIVE
#else
#define EVUTIL_AI_PASSIVE 0x1000
#endif
#if defined(AI_CANONNAME) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_CANONNAME AI_CANONNAME
#else
#define EVUTIL_AI_CANONNAME 0x2000
#endif
#if defined(AI_NUMERICHOST) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_NUMERICHOST AI_NUMERICHOST
#else
#define EVUTIL_AI_NUMERICHOST 0x4000
#endif
#if defined(AI_NUMERICSERV) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_NUMERICSERV AI_NUMERICSERV
#else
#define EVUTIL_AI_NUMERICSERV 0x8000
#endif
#if defined(AI_V4MAPPED) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_V4MAPPED AI_V4MAPPED
#else
#define EVUTIL_AI_V4MAPPED 0x10000
#endif
#if defined(AI_ALL) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_ALL AI_ALL
#else
#define EVUTIL_AI_ALL 0x20000
#endif
#if defined(AI_ADDRCONFIG) && defined(EVENT__HAVE_GETADDRINFO)
#define EVUTIL_AI_ADDRCONFIG AI_ADDRCONFIG
#else
#define EVUTIL_AI_ADDRCONFIG 0x40000
#endif
/**@}*/
struct evutil_addrinfo;
/**
* This function clones getaddrinfo for systems that don't have it. For full
* details, see RFC 3493, section 6.1.
*
* Limitations:
* - When the system has no getaddrinfo, we fall back to gethostbyname_r or
* gethostbyname, with their attendant issues.
* - The AI_V4MAPPED and AI_ALL flags are not currently implemented.
*
* For a nonblocking variant, see evdns_getaddrinfo.
*/
EVENT2_EXPORT_SYMBOL
int evutil_getaddrinfo(const char *nodename, const char *servname,
const struct evutil_addrinfo *hints_in, struct evutil_addrinfo **res);
/** Release storage allocated by evutil_getaddrinfo or evdns_getaddrinfo. */
EVENT2_EXPORT_SYMBOL
void evutil_freeaddrinfo(struct evutil_addrinfo *ai);
EVENT2_EXPORT_SYMBOL
const char *evutil_gai_strerror(int err);
/** Generate n bytes of secure pseudorandom data, and store them in buf.
*
* Current versions of Libevent use an ARC4-based random number generator,
* seeded using the platform's entropy source (/dev/urandom on Unix-like
* systems; CryptGenRandom on Windows). This is not actually as secure as it
* should be: ARC4 is a pretty lousy cipher, and the current implementation
* provides only rudimentary prediction- and backtracking-resistance. Don't
* use this for serious cryptographic applications.
*/
EVENT2_EXPORT_SYMBOL
void evutil_secure_rng_get_bytes(void *buf, size_t n);
/**
* Seed the secure random number generator if needed, and return 0 on
* success or -1 on failure.
*
* It is okay to call this function more than once; it will still return
* 0 if the RNG has been successfully seeded and -1 if it can't be
* seeded.
*
* Ordinarily you don't need to call this function from your own code;
* Libevent will seed the RNG itself the first time it needs good random
* numbers. You only need to call it if (a) you want to double-check
* that one of the seeding methods did succeed, or (b) you plan to drop
* the capability to seed (by chrooting, or dropping capabilities, or
* whatever), and you want to make sure that seeding happens before your
* program loses the ability to do it.
*/
EVENT2_EXPORT_SYMBOL
int evutil_secure_rng_init(void);
/**
* Set a filename to use in place of /dev/urandom for seeding the secure
* PRNG. Return 0 on success, -1 on failure.
*
* Call this function BEFORE calling any other initialization or RNG
* functions.
*
* (This string will _NOT_ be copied internally. Do not free it while any
* user of the secure RNG might be running. Don't pass anything other than a
* real /dev/...random device file here, or you might lose security.)
*
* This API is unstable, and might change in a future libevent version.
*/
EVENT2_EXPORT_SYMBOL
int evutil_secure_rng_set_urandom_device_file(char *fname);
/** Seed the random number generator with extra random bytes.
You should almost never need to call this function; it should be
sufficient to invoke evutil_secure_rng_init(), or let Libevent take
care of calling evutil_secure_rng_init() on its own.
If you call this function as a _replacement_ for the regular
entropy sources, then you need to be sure that your input
contains a fairly large amount of strong entropy. Doing so is
notoriously hard: most people who try get it wrong. Watch out!
@param dat a buffer full of a strong source of random numbers
@param datlen the number of bytes to read from datlen
*/
EVENT2_EXPORT_SYMBOL
void evutil_secure_rng_add_bytes(const char *dat, size_t datlen);
#ifdef __cplusplus
}
#endif
#endif /* EVENT1_EVUTIL_H_INCLUDED_ */

View File

@ -0,0 +1,50 @@
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* 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 EVENT2_VISIBILITY_H_INCLUDED_
#define EVENT2_VISIBILITY_H_INCLUDED_
#include <event2/event-config.h>
#if defined(event_EXPORTS) || defined(event_extra_EXPORTS) || defined(event_core_EXPORTS)
# if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550)
# define EVENT2_EXPORT_SYMBOL __global
# elif defined __GNUC__
# define EVENT2_EXPORT_SYMBOL __attribute__ ((visibility("default")))
# elif defined(_MSC_VER)
# define EVENT2_EXPORT_SYMBOL extern __declspec(dllexport)
# else
# define EVENT2_EXPORT_SYMBOL /* unknown compiler */
# endif
#else
# if defined(EVENT__NEED_DLLIMPORT) && defined(_MSC_VER) && !defined(EVENT_BUILDING_REGRESS_TEST)
# define EVENT2_EXPORT_SYMBOL extern __declspec(dllimport)
# else
# define EVENT2_EXPORT_SYMBOL
# endif
#endif
#endif /* EVENT2_VISIBILITY_H_INCLUDED_ */

View File

@ -0,0 +1,45 @@
/*
* 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 EVENT1_EVHTTP_H_INCLUDED_
#define EVENT1_EVHTTP_H_INCLUDED_
/** @file evhttp.h
An http implementation subsystem for Libevent.
The <evhttp.h> header is deprecated in Libevent 2.0 and later; please
use <event2/http.h> instead. Depending on what functionality you
need, you may also want to include more of the other <event2/...>
headers.
*/
#include <event.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <event2/http_compat.h>
#endif /* EVENT1_EVHTTP_H_INCLUDED_ */

View File

@ -0,0 +1,45 @@
/*
* 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 EVENT1_EVRPC_H_INCLUDED_
#define EVENT1_EVRPC_H_INCLUDED_
/** @file evrpc.h
An RPC system for Libevent.
The <evrpc.h> header is deprecated in Libevent 2.0 and later; please
use <event2/rpc.h> instead. Depending on what functionality you
need, you may also want to include more of the other <event2/...>
headers.
*/
#include <event.h>
#include <event2/rpc.h>
#include <event2/rpc_struct.h>
#include <event2/rpc_compat.h>
#endif /* EVENT1_EVRPC_H_INCLUDED_ */

View File

@ -0,0 +1,39 @@
/*
* 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 EVENT1_EVUTIL_H_INCLUDED_
#define EVENT1_EVUTIL_H_INCLUDED_
/** @file evutil.h
Utility and compatibility functions for Libevent.
The <evutil.h> header is deprecated in Libevent 2.0 and later; please
use <event2/util.h> instead.
*/
#include <event2/util.h>
#endif /* EVENT1_EVUTIL_H_INCLUDED_ */

View File

@ -0,0 +1,46 @@
# include/Makefile.am for libevent
# Copyright 2000-2007 Niels Provos
# Copyright 2007-2012 Niels Provos and Nick Mathewson
#
# See LICENSE for copying information.
include_event2dir = $(includedir)/event2
EVENT2_EXPORT = \
include/event2/buffer.h \
include/event2/buffer_compat.h \
include/event2/bufferevent.h \
include/event2/bufferevent_compat.h \
include/event2/bufferevent_ssl.h \
include/event2/bufferevent_struct.h \
include/event2/dns.h \
include/event2/dns_compat.h \
include/event2/dns_struct.h \
include/event2/event.h \
include/event2/event_compat.h \
include/event2/event_struct.h \
include/event2/http.h \
include/event2/http_compat.h \
include/event2/http_struct.h \
include/event2/keyvalq_struct.h \
include/event2/listener.h \
include/event2/rpc.h \
include/event2/rpc_compat.h \
include/event2/rpc_struct.h \
include/event2/tag.h \
include/event2/tag_compat.h \
include/event2/thread.h \
include/event2/util.h \
include/event2/visibility.h
## Without the nobase_ prefixing, Automake would strip "include/event2/" from
## the source header filename to derive the installed header filename.
## With nobase_ the installed path is $(includedir)/include/event2/ev*.h.
if INSTALL_LIBEVENT
include_event2_HEADERS = $(EVENT2_EXPORT)
nodist_include_event2_HEADERS = include/event2/event-config.h
else
noinst_HEADERS += $(EVENT2_EXPORT)
nodist_noinst_HEADERS = include/event2/event-config.h
endif

501
contrib/libevent/install-sh Executable file
View File

@ -0,0 +1,501 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# 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
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -0,0 +1,201 @@
/*
* 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

View File

@ -0,0 +1,83 @@
/*
* 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

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 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 KQUEUE_INTERNAL_H_INCLUDED_
#define KQUEUE_INTERNAL_H_INCLUDED_
/** Notification function, used to tell an event base to wake up from another
* thread. Only works when event_kq_add_notify_event_() has previously been
* called successfully on that base. */
int event_kq_notify_base_(struct event_base *base);
/** Prepare a kqueue-using event base to receive notifications via an internal
* EVFILT_USER event. Return 0 on sucess, -1 on failure.
*/
int event_kq_add_notify_event_(struct event_base *base);
#endif

567
contrib/libevent/kqueue.c Normal file
View File

@ -0,0 +1,567 @@
/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art 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 EVENT__HAVE_KQUEUE
#include <sys/types.h>
#ifdef EVENT__HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <sys/queue.h>
#include <sys/event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#ifdef EVENT__HAVE_INTTYPES_H
#include <inttypes.h>
#endif
/* Some platforms apparently define the udata field of struct kevent as
* intptr_t, whereas others define it as void*. There doesn't seem to be an
* easy way to tell them apart via autoconf, so we need to use OS macros. */
#if defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__)
#define PTR_TO_UDATA(x) ((intptr_t)(x))
#define INT_TO_UDATA(x) ((intptr_t)(x))
#else
#define PTR_TO_UDATA(x) (x)
#define INT_TO_UDATA(x) ((void*)(x))
#endif
#include "event-internal.h"
#include "log-internal.h"
#include "evmap-internal.h"
#include "event2/thread.h"
#include "evthread-internal.h"
#include "changelist-internal.h"
#include "kqueue-internal.h"
#define NEVENT 64
struct kqop {
struct kevent *changes;
int changes_size;
struct kevent *events;
int events_size;
int kq;
int notify_event_added;
pid_t pid;
};
static void kqop_free(struct kqop *kqop);
static void *kq_init(struct event_base *);
static int kq_sig_add(struct event_base *, int, short, short, void *);
static int kq_sig_del(struct event_base *, int, short, short, void *);
static int kq_dispatch(struct event_base *, struct timeval *);
static void kq_dealloc(struct event_base *);
const struct eventop kqops = {
"kqueue",
kq_init,
event_changelist_add_,
event_changelist_del_,
kq_dispatch,
kq_dealloc,
1 /* need reinit */,
EV_FEATURE_ET|EV_FEATURE_O1|EV_FEATURE_FDS,
EVENT_CHANGELIST_FDINFO_SIZE
};
static const struct eventop kqsigops = {
"kqueue_signal",
NULL,
kq_sig_add,
kq_sig_del,
NULL,
NULL,
1 /* need reinit */,
0,
0
};
static void *
kq_init(struct event_base *base)
{
int kq = -1;
struct kqop *kqueueop = NULL;
if (!(kqueueop = mm_calloc(1, sizeof(struct kqop))))
return (NULL);
/* Initialize the kernel queue */
if ((kq = kqueue()) == -1) {
event_warn("kqueue");
goto err;
}
kqueueop->kq = kq;
kqueueop->pid = getpid();
/* Initialize fields */
kqueueop->changes = mm_calloc(NEVENT, sizeof(struct kevent));
if (kqueueop->changes == NULL)
goto err;
kqueueop->events = mm_calloc(NEVENT, sizeof(struct kevent));
if (kqueueop->events == NULL)
goto err;
kqueueop->events_size = kqueueop->changes_size = NEVENT;
/* Check for Mac OS X kqueue bug. */
memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
kqueueop->changes[0].ident = -1;
kqueueop->changes[0].filter = EVFILT_READ;
kqueueop->changes[0].flags = EV_ADD;
/*
* If kqueue works, then kevent will succeed, and it will
* stick an error in events[0]. If kqueue is broken, then
* kevent will fail.
*/
if (kevent(kq,
kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
(int)kqueueop->events[0].ident != -1 ||
!(kqueueop->events[0].flags & EV_ERROR)) {
event_warn("%s: detected broken kqueue; not using.", __func__);
goto err;
}
base->evsigsel = &kqsigops;
return (kqueueop);
err:
if (kqueueop)
kqop_free(kqueueop);
return (NULL);
}
#define ADD_UDATA 0x30303
static void
kq_setup_kevent(struct kevent *out, evutil_socket_t fd, int filter, short change)
{
memset(out, 0, sizeof(struct kevent));
out->ident = fd;
out->filter = filter;
if (change & EV_CHANGE_ADD) {
out->flags = EV_ADD;
/* We set a magic number here so that we can tell 'add'
* errors from 'del' errors. */
out->udata = INT_TO_UDATA(ADD_UDATA);
if (change & EV_ET)
out->flags |= EV_CLEAR;
#ifdef NOTE_EOF
/* Make it behave like select() and poll() */
if (filter == EVFILT_READ)
out->fflags = NOTE_EOF;
#endif
} else {
EVUTIL_ASSERT(change & EV_CHANGE_DEL);
out->flags = EV_DELETE;
}
}
static int
kq_build_changes_list(const struct event_changelist *changelist,
struct kqop *kqop)
{
int i;
int n_changes = 0;
for (i = 0; i < changelist->n_changes; ++i) {
struct event_change *in_ch = &changelist->changes[i];
struct kevent *out_ch;
if (n_changes >= kqop->changes_size - 1) {
int newsize = kqop->changes_size * 2;
struct kevent *newchanges;
newchanges = mm_realloc(kqop->changes,
newsize * sizeof(struct kevent));
if (newchanges == NULL) {
event_warn("%s: realloc", __func__);
return (-1);
}
kqop->changes = newchanges;
kqop->changes_size = newsize;
}
if (in_ch->read_change) {
out_ch = &kqop->changes[n_changes++];
kq_setup_kevent(out_ch, in_ch->fd, EVFILT_READ,
in_ch->read_change);
}
if (in_ch->write_change) {
out_ch = &kqop->changes[n_changes++];
kq_setup_kevent(out_ch, in_ch->fd, EVFILT_WRITE,
in_ch->write_change);
}
}
return n_changes;
}
static int
kq_grow_events(struct kqop *kqop, size_t new_size)
{
struct kevent *newresult;
newresult = mm_realloc(kqop->events,
new_size * sizeof(struct kevent));
if (newresult) {
kqop->events = newresult;
kqop->events_size = new_size;
return 0;
} else {
return -1;
}
}
static int
kq_dispatch(struct event_base *base, struct timeval *tv)
{
struct kqop *kqop = base->evbase;
struct kevent *events = kqop->events;
struct kevent *changes;
struct timespec ts, *ts_p = NULL;
int i, n_changes, res;
if (tv != NULL) {
ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000;
ts_p = &ts;
}
/* Build "changes" from "base->changes" */
EVUTIL_ASSERT(kqop->changes);
n_changes = kq_build_changes_list(&base->changelist, kqop);
if (n_changes < 0)
return -1;
event_changelist_remove_all_(&base->changelist, base);
/* steal the changes array in case some broken code tries to call
* dispatch twice at once. */
changes = kqop->changes;
kqop->changes = NULL;
/* Make sure that 'events' is at least as long as the list of changes:
* otherwise errors in the changes can get reported as a -1 return
* value from kevent() rather than as EV_ERROR events in the events
* array.
*
* (We could instead handle -1 return values from kevent() by
* retrying with a smaller changes array or a larger events array,
* but this approach seems less risky for now.)
*/
if (kqop->events_size < n_changes) {
int new_size = kqop->events_size;
do {
new_size *= 2;
} while (new_size < n_changes);
kq_grow_events(kqop, new_size);
events = kqop->events;
}
EVBASE_RELEASE_LOCK(base, th_base_lock);
res = kevent(kqop->kq, changes, n_changes,
events, kqop->events_size, ts_p);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
EVUTIL_ASSERT(kqop->changes == NULL);
kqop->changes = changes;
if (res == -1) {
if (errno != EINTR) {
event_warn("kevent");
return (-1);
}
return (0);
}
event_debug(("%s: kevent reports %d", __func__, res));
for (i = 0; i < res; i++) {
int which = 0;
if (events[i].flags & EV_ERROR) {
switch (events[i].data) {
/* Can occur on delete if we are not currently
* watching any events on this fd. That can
* happen when the fd was closed and another
* file was opened with that fd. */
case ENOENT:
/* Can occur for reasons not fully understood
* on FreeBSD. */
case EINVAL:
continue;
#if defined(__FreeBSD__)
/*
* This currently occurs if an FD is closed
* before the EV_DELETE makes it out via kevent().
* The FreeBSD capabilities code sees the blank
* capability set and rejects the request to
* modify an event.
*
* To be strictly correct - when an FD is closed,
* all the registered events are also removed.
* Queuing EV_DELETE to a closed FD is wrong.
* The event(s) should just be deleted from
* the pending changelist.
*/
case ENOTCAPABLE:
continue;
#endif
/* Can occur on a delete if the fd is closed. */
case EBADF:
/* XXXX On NetBSD, we can also get EBADF if we
* try to add the write side of a pipe, but
* the read side has already been closed.
* Other BSDs call this situation 'EPIPE'. It
* would be good if we had a way to report
* this situation. */
continue;
/* These two can occur on an add if the fd was one side
* of a pipe, and the other side was closed. */
case EPERM:
case EPIPE:
/* Report read events, if we're listening for
* them, so that the user can learn about any
* add errors. (If the operation was a
* delete, then udata should be cleared.) */
if (events[i].udata) {
/* The operation was an add:
* report the error as a read. */
which |= EV_READ;
break;
} else {
/* The operation was a del:
* report nothing. */
continue;
}
/* Other errors shouldn't occur. */
default:
errno = events[i].data;
return (-1);
}
} else if (events[i].filter == EVFILT_READ) {
which |= EV_READ;
} else if (events[i].filter == EVFILT_WRITE) {
which |= EV_WRITE;
} else if (events[i].filter == EVFILT_SIGNAL) {
which |= EV_SIGNAL;
#ifdef EVFILT_USER
} else if (events[i].filter == EVFILT_USER) {
base->is_notify_pending = 0;
#endif
}
if (!which)
continue;
if (events[i].filter == EVFILT_SIGNAL) {
evmap_signal_active_(base, events[i].ident, 1);
} else {
evmap_io_active_(base, events[i].ident, which | EV_ET);
}
}
if (res == kqop->events_size) {
/* We used all the events space that we have. Maybe we should
make it bigger. */
kq_grow_events(kqop, kqop->events_size * 2);
}
return (0);
}
static void
kqop_free(struct kqop *kqop)
{
if (kqop->changes)
mm_free(kqop->changes);
if (kqop->events)
mm_free(kqop->events);
if (kqop->kq >= 0 && kqop->pid == getpid())
close(kqop->kq);
memset(kqop, 0, sizeof(struct kqop));
mm_free(kqop);
}
static void
kq_dealloc(struct event_base *base)
{
struct kqop *kqop = base->evbase;
evsig_dealloc_(base);
kqop_free(kqop);
}
/* signal handling */
static int
kq_sig_add(struct event_base *base, int nsignal, short old, short events, void *p)
{
struct kqop *kqop = base->evbase;
struct kevent kev;
struct timespec timeout = { 0, 0 };
(void)p;
EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
memset(&kev, 0, sizeof(kev));
kev.ident = nsignal;
kev.filter = EVFILT_SIGNAL;
kev.flags = EV_ADD;
/* Be ready for the signal if it is sent any
* time between now and the next call to
* kq_dispatch. */
if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
return (-1);
/* We can set the handler for most signals to SIG_IGN and
* still have them reported to us in the queue. However,
* if the handler for SIGCHLD is SIG_IGN, the system reaps
* zombie processes for us, and we don't get any notification.
* This appears to be the only signal with this quirk. */
if (evsig_set_handler_(base, nsignal,
nsignal == SIGCHLD ? SIG_DFL : SIG_IGN) == -1)
return (-1);
return (0);
}
static int
kq_sig_del(struct event_base *base, int nsignal, short old, short events, void *p)
{
struct kqop *kqop = base->evbase;
struct kevent kev;
struct timespec timeout = { 0, 0 };
(void)p;
EVUTIL_ASSERT(nsignal >= 0 && nsignal < NSIG);
memset(&kev, 0, sizeof(kev));
kev.ident = nsignal;
kev.filter = EVFILT_SIGNAL;
kev.flags = EV_DELETE;
/* Because we insert signal events
* immediately, we need to delete them
* immediately, too */
if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
return (-1);
if (evsig_restore_handler_(base, nsignal) == -1)
return (-1);
return (0);
}
/* OSX 10.6 and FreeBSD 8.1 add support for EVFILT_USER, which we can use
* to wake up the event loop from another thread. */
/* Magic number we use for our filter ID. */
#define NOTIFY_IDENT 42
int
event_kq_add_notify_event_(struct event_base *base)
{
struct kqop *kqop = base->evbase;
#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
struct kevent kev;
struct timespec timeout = { 0, 0 };
#endif
if (kqop->notify_event_added)
return 0;
#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
memset(&kev, 0, sizeof(kev));
kev.ident = NOTIFY_IDENT;
kev.filter = EVFILT_USER;
kev.flags = EV_ADD | EV_CLEAR;
if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
event_warn("kevent: adding EVFILT_USER event");
return -1;
}
kqop->notify_event_added = 1;
return 0;
#else
return -1;
#endif
}
int
event_kq_notify_base_(struct event_base *base)
{
struct kqop *kqop = base->evbase;
#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
struct kevent kev;
struct timespec timeout = { 0, 0 };
#endif
if (! kqop->notify_event_added)
return -1;
#if defined(EVFILT_USER) && defined(NOTE_TRIGGER)
memset(&kev, 0, sizeof(kev));
kev.ident = NOTIFY_IDENT;
kev.filter = EVFILT_USER;
kev.fflags = NOTE_TRIGGER;
if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1) {
event_warn("kevent: triggering EVFILT_USER event");
return -1;
}
return 0;
#else
return -1;
#endif
}
#endif /* EVENT__HAVE_KQUEUE */

View File

@ -0,0 +1,16 @@
#libevent pkg-config source file
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libevent
Description: libevent is an asynchronous notification event loop library
Version: @VERSION@
Requires:
Conflicts:
Libs: -L${libdir} -levent
Libs.private: @LIBS@
Cflags: -I${includedir}

Some files were not shown because too many files have changed in this diff Show More