mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
merge.
checkpoint. does not compile.
This commit is contained in:
2384
.bzrignore
2384
.bzrignore
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
cflags="$c_warnings $extra_flags"
|
||||
cxxflags="$cxx_warnings $base_cxxflags $extra_flags"
|
||||
extra_configs="$extra_configs $local_infile_configs"
|
||||
cflags="$c_warnings $extra_flags $EXTRA_FLAGS $EXTRA_CFLAGS"
|
||||
cxxflags="$cxx_warnings $base_cxxflags $extra_flags $EXTRA_FLAGS $EXTRA_CXXFLAGS"
|
||||
extra_configs="$extra_configs $local_infile_configs $EXTRA_CONFIGS"
|
||||
configure="./configure $base_configs $extra_configs"
|
||||
|
||||
commands="\
|
||||
|
||||
@@ -33,6 +33,7 @@ EXTRA_DIST = FINISH.sh \
|
||||
compile-amd64-max \
|
||||
compile-amd64-max-sci \
|
||||
compile-amd64-valgrind-max \
|
||||
compile-bintar \
|
||||
compile-darwin-mwcc \
|
||||
compile-dist \
|
||||
compile-hpux11-parisc2-aCC \
|
||||
@@ -69,9 +70,14 @@ EXTRA_DIST = FINISH.sh \
|
||||
compile-ppc-max \
|
||||
compile-solaris-amd64 \
|
||||
compile-solaris-amd64-debug \
|
||||
compile-solaris-amd64-debug-forte \
|
||||
compile-solaris-amd64-forte \
|
||||
compile-solaris-amd64-forte-debug \
|
||||
compile-solaris-sparc \
|
||||
compile-solaris-sparc-debug \
|
||||
compile-solaris-sparc-forte \
|
||||
compile-solaris-sparc-purify
|
||||
compile-solaris-sparc-purify \
|
||||
compile-solaris-x86-32 \
|
||||
compile-solaris-x86-32-debug \
|
||||
compile-solaris-x86-32-debug-forte \
|
||||
compile-solaris-x86-forte-32 \
|
||||
util.sh
|
||||
|
||||
@@ -31,6 +31,14 @@ parse_options()
|
||||
prefix=`get_key_value "$1"`;;
|
||||
--warning-mode=*)
|
||||
warning_mode=`get_key_value "$1"`;;
|
||||
--extra-flags=*)
|
||||
EXTRA_FLAGS=`get_key_value "$1"`;;
|
||||
--extra-cflags=*)
|
||||
EXTRA_CFLAGS=`get_key_value "$1"`;;
|
||||
--extra-cxxflags=*)
|
||||
EXTRA_CXXFLAGS=`get_key_value "$1"`;;
|
||||
--extra-configs=*)
|
||||
EXTRA_CONFIGS=`get_key_value "$1"`;;
|
||||
-c | --just-configure)
|
||||
just_configure=1;;
|
||||
-n | --just-print | --print)
|
||||
@@ -75,13 +83,13 @@ set -e
|
||||
#
|
||||
path=`dirname $0`
|
||||
. "$path/check-cpu"
|
||||
. "$path/util.sh"
|
||||
|
||||
export AM_MAKEFLAGS
|
||||
AM_MAKEFLAGS="-j 6"
|
||||
get_make_parallel_flag
|
||||
|
||||
# SSL library to use.--with-ssl will select our bundled yaSSL
|
||||
# implementation of SSL. To use openSSl you will nee too point out
|
||||
# the location of openSSL headers and lbs on your system.
|
||||
# implementation of SSL. To use OpenSSL you will need to specify
|
||||
# the location of OpenSSL headers and libs on your system.
|
||||
# Ex --with-ssl=/usr
|
||||
SSL_LIBRARY=--with-ssl
|
||||
|
||||
@@ -139,6 +147,13 @@ fast_cflags="-O3 -fno-omit-frame-pointer"
|
||||
debug_configs="--with-debug"
|
||||
debug_cflags="$debug_cflags $debug_extra_cflags"
|
||||
|
||||
static_link="--with-mysqld-ldflags=-all-static "
|
||||
static_link="$static_link --with-client-ldflags=-all-static"
|
||||
# we need local-infile in all binaries for rpl000001
|
||||
# if you need to disable local-infile in the client, write a build script
|
||||
# and unset local_infile_configs
|
||||
local_infile_configs="--enable-local-infile"
|
||||
|
||||
#
|
||||
# Configuration options.
|
||||
#
|
||||
@@ -146,6 +161,9 @@ base_configs="--prefix=$prefix --enable-assembler "
|
||||
base_configs="$base_configs --with-extra-charsets=complex "
|
||||
base_configs="$base_configs --enable-thread-safe-client "
|
||||
base_configs="$base_configs --with-big-tables $maintainer_mode"
|
||||
base_configs="$base_configs --with-plugin-aria --with-aria-tmp-tables --without-plugin-innodb_plugin"
|
||||
# Compile our client programs with static libraries to allow them to be moved
|
||||
base_configs="$base_configs --with-mysqld-ldflags=-static --with-client-ldflags=-static"
|
||||
|
||||
if test -d "$path/../cmd-line-utils/readline"
|
||||
then
|
||||
@@ -155,17 +173,11 @@ then
|
||||
base_configs="$base_configs --with-libedit"
|
||||
fi
|
||||
|
||||
static_link="--with-mysqld-ldflags=-all-static "
|
||||
static_link="$static_link --with-client-ldflags=-all-static"
|
||||
# we need local-infile in all binaries for rpl000001
|
||||
# if you need to disable local-infile in the client, write a build script
|
||||
# and unset local_infile_configs
|
||||
local_infile_configs="--enable-local-infile"
|
||||
|
||||
|
||||
max_no_embedded_configs="$SSL_LIBRARY --with-plugins=max"
|
||||
max_no_ndb_configs="$SSL_LIBRARY --with-plugins=max-no-ndb --with-embedded-server"
|
||||
max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server"
|
||||
max_no_qc_configs="$SSL_LIBRARY --with-plugins=max --without-query-cache"
|
||||
max_no_ndb_configs="$SSL_LIBRARY --with-plugins=max-no-ndb --with-embedded-server --with-libevent"
|
||||
max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server --with-libevent"
|
||||
all_configs="$SSL_LIBRARY --with-plugins=max --with-plugin-ndbcluster --with-embedded-server --with-innodb_plugin --with-libevent"
|
||||
|
||||
#
|
||||
# CPU and platform specific compilation flags.
|
||||
@@ -190,7 +202,7 @@ if test -z "$CC" ; then
|
||||
fi
|
||||
|
||||
if test -z "$CXX" ; then
|
||||
CXX=gcc
|
||||
CXX=g++
|
||||
fi
|
||||
|
||||
# If ccache (a compiler cache which reduces build time)
|
||||
|
||||
7
BUILD/compile-amd64-debug-all
Executable file
7
BUILD/compile-amd64-debug-all
Executable file
@@ -0,0 +1,7 @@
|
||||
#! /bin/sh
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
extra_flags="$amd64_cflags $debug_cflags"
|
||||
extra_configs="$amd64_configs $debug_configs $all_configs"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
7
BUILD/compile-amd64-gprof-no-ndb
Executable file
7
BUILD/compile-amd64-gprof-no-ndb
Executable file
@@ -0,0 +1,7 @@
|
||||
#! /bin/sh
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
extra_flags="$amd64_cflags -pg -g"
|
||||
extra_configs="$amd64_configs $max_no_ndb_configs --disable-shared $static_link"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
79
BUILD/compile-bintar
Executable file
79
BUILD/compile-bintar
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# MariaDB SQL server.
|
||||
# Copyright (C) 2010 Kristian Nielsen and Monty Program AB
|
||||
#
|
||||
# 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; version 2 of the License.
|
||||
#
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
# This script's purpose is to build the binary tarball packages for MariaDB
|
||||
# (currently only on Linux systems).
|
||||
#
|
||||
# Thus BUILD/compile-bintar from the appropriate source tarball will reproduce
|
||||
# such a release, provided the build environment (gcc version etc.) matches
|
||||
# (use scripts/make_binary_distribution after running this script to actually
|
||||
# create the binary tarball package).
|
||||
#
|
||||
# Note that packages are built from source tarballs not bzr checkouts.
|
||||
# Therefore, this script assumes autotools have already been run.
|
||||
#
|
||||
# We link libc dynamically, otherwise we get lots of problems loading
|
||||
# .so files at runtime (either system stuff like NSS, or server
|
||||
# plugins).
|
||||
#
|
||||
# We link libgcc statically to avoid reduce nasty library version dependencies.
|
||||
|
||||
test -f Makefile && make distclean
|
||||
|
||||
path=`dirname $0`
|
||||
. $path/util.sh
|
||||
|
||||
SYSTEM_TYPE="$(uname -o)"
|
||||
MACHINE_TYPE="$(uname -m)"
|
||||
|
||||
# We cannot have a slash '/' in tarfile name.
|
||||
SYSTEM_TYPE="$(echo ${SYSTEM_TYPE} | sed -e 's/GNU\///')"
|
||||
|
||||
# Get correct options for architecture into CPUOPT.
|
||||
get_cpuopt
|
||||
# Get correct -j option into AM_MAKEFLAGS
|
||||
get_make_parallel_flag
|
||||
|
||||
# Use gcc rather than g++ to avoid linking libstdc++.so (which we don't need).
|
||||
FLAGS="-O2 -fno-omit-frame-pointer -g -pipe -Wall $CPUOPT"
|
||||
|
||||
# Don't press on in case of error.
|
||||
set -e
|
||||
|
||||
CC="gcc -static-libgcc" CXX="g++ -static-libgcc" CFLAGS="$FLAGS" CXXFLAGS="$FLAGS" \
|
||||
./configure \
|
||||
--prefix=/usr/local/mysql \
|
||||
--exec-prefix=/usr/local/mysql \
|
||||
--libexecdir=/usr/local/mysql/bin \
|
||||
--localstatedir=/usr/local/mysql/data \
|
||||
\
|
||||
--with-comment="(MariaDB - http://mariadb.com/)" \
|
||||
--with-system-type="${SYSTEM_TYPE}" \
|
||||
--with-machine-type="${MACHINE_TYPE}" \
|
||||
\
|
||||
--enable-shared --enable-static \
|
||||
--with-client-ldflags=-static --with-mysqld-ldflags=-static \
|
||||
--enable-thread-safe-client --enable-local-infile --with-big-tables \
|
||||
--without-docs --with-extra-charsets=all \
|
||||
--with-libwrap --with-ssl --with-readline --with-libevent --with-zlib-dir=bundled \
|
||||
--with-partition --with-embedded-server \
|
||||
--with-plugins=max-no-ndb \
|
||||
--without-plugin-innodb_plugin
|
||||
|
||||
make $AM_MAKEFLAGS
|
||||
@@ -78,6 +78,5 @@ fi
|
||||
./configure \
|
||||
--with-embedded-server \
|
||||
--with-perfschema \
|
||||
--with-ndbcluster
|
||||
$gmake
|
||||
|
||||
--with-plugins=max-no-ndb
|
||||
$gmake -j4
|
||||
|
||||
24
BUILD/compile-innodb
Executable file
24
BUILD/compile-innodb
Executable file
@@ -0,0 +1,24 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
|
||||
#
|
||||
# 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; version 2 of the License.
|
||||
#
|
||||
# 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, write to the Free Software Foundation, Inc., 59 Temple
|
||||
# Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium_cflags $fast_cflags -g"
|
||||
extra_configs="$pentium_configs $static_link --with-plugins=innobase"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
24
BUILD/compile-innodb-debug
Executable file
24
BUILD/compile-innodb-debug
Executable file
@@ -0,0 +1,24 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
|
||||
#
|
||||
# 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; version 2 of the License.
|
||||
#
|
||||
# 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, write to the Free Software Foundation, Inc., 59 Temple
|
||||
# Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh" $@ --with-debug=full
|
||||
|
||||
extra_flags="$pentium_cflags $debug_cflags"
|
||||
extra_configs="$pentium_configs $debug_configs --with-plugins=innobase"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
@@ -4,7 +4,7 @@ path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium_cflags $fast_cflags"
|
||||
extra_configs="$pentium_configs $static_link"
|
||||
extra_configs="$pentium_configs"
|
||||
strip=yes
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
10
BUILD/compile-pentium-debug-all
Executable file
10
BUILD/compile-pentium-debug-all
Executable file
@@ -0,0 +1,10 @@
|
||||
#! /bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
set -- "$@" --with-debug=full
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium_cflags $debug_cflags"
|
||||
extra_configs="$pentium_configs $debug_configs $all_configs $error_inject --with-experimental-collations"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
10
BUILD/compile-pentium-debug-max-no-qc
Executable file
10
BUILD/compile-pentium-debug-max-no-qc
Executable file
@@ -0,0 +1,10 @@
|
||||
#! /bin/sh
|
||||
# Builds server without query cache support
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium_cflags $debug_cflags"
|
||||
extra_configs="$pentium_configs $debug_configs $max_no_qc_configs"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
12
BUILD/compile-pentium64-debug-all
Executable file
12
BUILD/compile-pentium64-debug-all
Executable file
@@ -0,0 +1,12 @@
|
||||
#! /bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
set -- "$@" --with-debug=full
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium64_cflags $debug_cflags"
|
||||
extra_configs="$pentium_configs $debug_configs $all_configs"
|
||||
|
||||
extra_configs="$extra_configs "
|
||||
CC="$CC --pipe"
|
||||
. "$path/FINISH.sh"
|
||||
@@ -9,9 +9,9 @@ export CCACHE_DISABLE
|
||||
|
||||
export LDFLAGS="$gcov_link_flags"
|
||||
|
||||
extra_flags="$pentium64_cflags $debug_cflags $max_cflags $gcov_compile_flags"
|
||||
extra_flags="$pentium64_cflags $max_cflags $gcov_compile_flags"
|
||||
c_warnings="$c_warnings $debug_extra_warnings"
|
||||
cxx_warnings="$cxx_warnings $debug_extra_warnings"
|
||||
extra_configs="$pentium64_configs $debug_configs $gcov_configs $max_configs"
|
||||
extra_configs="$pentium_configs $debug_configs $gcov_configs $max_configs --with-zlib-dir=bundled"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
@@ -4,6 +4,6 @@ path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium64_cflags $gprof_compile_flags"
|
||||
extra_configs="$pentium64_configs $debug_configs $gprof_link_flags"
|
||||
extra_configs="$pentium_configs $max_configs $gprof_link_flags --with-zlib-dir=bundled"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
@@ -4,7 +4,10 @@ path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium64_cflags $fast_cflags"
|
||||
extra_configs="$pentium_configs $max_configs $static_link"
|
||||
# On CentOS/Fedora Core 10 amd64, there is system libz.so but not
|
||||
# libz.a, so need to use bundled zlib when building static
|
||||
# binary. Hence we use --with-zlib-dir=bundled
|
||||
extra_configs="$pentium_configs $max_configs $static_link --with-zlib-dir=bundled"
|
||||
CC="$CC --pipe"
|
||||
strip=yes
|
||||
|
||||
|
||||
@@ -1,55 +1,32 @@
|
||||
#!/usr/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
function _find_mysql_root () (
|
||||
while [ "x$PWD" != "x/" ]; do
|
||||
# Check if some directories are present
|
||||
if [ -d BUILD -a -d sql -a -d mysys ]; then
|
||||
echo "$PWD"
|
||||
return 0
|
||||
fi
|
||||
cd ..
|
||||
done
|
||||
return 1
|
||||
)
|
||||
# Build setup for Solaris 10
|
||||
|
||||
make -k clean || true
|
||||
/bin/rm -f */.deps/*.P config.cache
|
||||
# Make the Sun Freeware packages use the bundled Perl, instead of their own:
|
||||
# ln -s `which perl` /usr/local/bin
|
||||
# Your $PATH needs to include (in this order):
|
||||
# /usr/local/bin:/usr/sfw/bin:/usr/ccs/bin
|
||||
# (For Sun Freeware, bundled GNU utilities, Solaris ar, etc.)
|
||||
#
|
||||
# Required packages from http://sunfreeware.com/indexintel10.html :
|
||||
# (The GNU m4 bundled with Solaris is too old.)
|
||||
# automake-1.10.2-sol10-x86-local.gz
|
||||
# autoconf-2.63-sol10-x86-local.gz
|
||||
# m4-1.4.12-sol10-x86-local.gz
|
||||
# libsigsegv-2.6-sol10-x86-local.gz
|
||||
# libtool-1.5.24-sol10-x86-local.gz
|
||||
# ( how to install these packages:
|
||||
# wget ftp://ftp.sunfreeware.com/pub/freeware/intel/10/automake-1.10.2-sol10-x86-local.gz
|
||||
# gunzip automake-1.10.2-sol10-x86-local.gz
|
||||
# pkgadd -d automake-1.10.2-sol10-x86-local
|
||||
# )
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
. "$path/SETUP.sh"
|
||||
extra_flags="$amd64_cflags -D__sun -m64 -mtune=athlon64"
|
||||
extra_configs="$amd64_configs $max_configs --with-libevent"
|
||||
|
||||
warning_flags="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused"
|
||||
compiler_flags="-g -O3 -fno-omit-frame-pointer"
|
||||
LDFLAGS="-lmtmalloc -R/usr/sfw/lib/64"
|
||||
export LDFLAGS
|
||||
|
||||
export CC CXX CFLAGS CXXFLAGS LDFLAGS LIBS
|
||||
CC="gcc"
|
||||
CXX="gcc"
|
||||
CFLAGS="$warning_flags $compiler_flags"
|
||||
CXXFLAGS=""
|
||||
LDFLAGS="-O3 -g -static-libgcc"
|
||||
LIBS=-lmtmalloc
|
||||
root=$(_find_mysql_root)
|
||||
|
||||
$root/configure \
|
||||
--prefix=/usr/local/mysql \
|
||||
--localstatedir=/usr/local/mysql/data \
|
||||
--libexecdir=/usr/local/mysql/bin \
|
||||
--with-extra-charsets=complex \
|
||||
--enable-thread-safe-client \
|
||||
--enable-local-infile \
|
||||
--with-zlib-dir=bundled \
|
||||
--with-big-tables \
|
||||
--with-readline \
|
||||
--with-archive-storage-engine \
|
||||
--with-named-curses=-lcurses \
|
||||
--with-big-tables \
|
||||
--with-innodb \
|
||||
--with-berkeley-db \
|
||||
--with-example-storage-engine \
|
||||
--with-blackhole-storage-engine \
|
||||
--with-ndbcluster \
|
||||
--with-federated-storage-engine \
|
||||
--with-csv-storage-engine \
|
||||
--with-ssl \
|
||||
--with-embedded-server \
|
||||
--disable-shared
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
11
BUILD/compile-solaris-amd64-debug
Normal file → Executable file
11
BUILD/compile-solaris-amd64-debug
Normal file → Executable file
@@ -1,10 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
amd64_cflags="-m64 -mtune=athlon64"
|
||||
extra_flags="$amd64_cflags $debug_cflags $max_cflags"
|
||||
c_warnings="$c_warnings $debug_extra_warnings"
|
||||
cxx_warnings="$cxx_warnings $debug_extra_warnings"
|
||||
extra_configs="$amd64_configs $debug_configs $max_configs --enable-thread-safe-client"
|
||||
extra_flags="$amd64_cflags -D__sun -m64 -mtune=athlon64 $debug_cflags"
|
||||
extra_configs="$amd64_configs $debug_configs $max_configs --with-libevent"
|
||||
|
||||
LDFLAGS="-lmtmalloc -R/usr/sfw/lib/64"
|
||||
export LDFLAGS
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
27
BUILD/compile-solaris-amd64-debug-forte
Executable file
27
BUILD/compile-solaris-amd64-debug-forte
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
# Take only #define options - the others are gcc specific.
|
||||
# (real fix is for SETUP.sh not to put gcc specific options in $debug_cflags)
|
||||
DEFS=""
|
||||
for F in $debug_cflags ; do
|
||||
expr "$F" : "^-D" && DEFS="$DEFS $F"
|
||||
done
|
||||
debug_cflags="-O0 -g $DEFS"
|
||||
|
||||
extra_flags="-m64 -mt -D_FORTEC_ -xlibmopt -fns=no $debug_cflags"
|
||||
extra_configs="$max_configs --with-libevent $debug_configs"
|
||||
|
||||
warnings=""
|
||||
c_warnings=""
|
||||
cxx_warnings=""
|
||||
base_cxxflags="-noex"
|
||||
|
||||
CC=cc
|
||||
CFLAGS="-xstrconst"
|
||||
CXX=CC
|
||||
LDFLAGS="-lmtmalloc"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
@@ -1,53 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
gmake -k clean || true
|
||||
/bin/rm -f */.deps/*.P config.cache
|
||||
# See file compile-solaris-amd64 for basic pre-requisites.
|
||||
|
||||
# This build uses the Sun Studio compilers (cc, CC), available from:
|
||||
# http://developers.sun.com/sunstudio/downloads/index.jsp
|
||||
# Note that you may want to apply current patches, as the downloaded version
|
||||
# is typically out of date. Download the PKG version if you intend to patch!
|
||||
|
||||
# After installing, add /opt/SUNWspro/bin to your $PATH
|
||||
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
# For "optimal" code for this computer add -fast to EXTRA
|
||||
# To compile 64 bit, add -m64 to EXTRA_64_BIT
|
||||
extra_flags="-m64 -mt -D_FORTEC_ -xbuiltin=%all -xlibmil -xlibmopt -fns=no -xprefetch=auto -xprefetch_level=3"
|
||||
extra_configs="$max_configs --with-libevent"
|
||||
|
||||
EXTRA_64_BIT="-m64"
|
||||
EXTRA="-fast"
|
||||
warnings=""
|
||||
c_warnings=""
|
||||
cxx_warnings=""
|
||||
base_cxxflags="-noex"
|
||||
|
||||
#
|
||||
# The following should not need to be touched
|
||||
#
|
||||
|
||||
export CC CXX CFLAGS CXXFLAGS LIBS
|
||||
STD="-g -mt -D_FORTEC_ $EXTRA $EXTRA_64_BIT"
|
||||
ASFLAGS="$EXTRA_64_BIT"
|
||||
CC=cc-5.0
|
||||
CFLAGS="-Xa -xstrconst $STD"
|
||||
CC=cc
|
||||
CFLAGS="-xstrconst"
|
||||
CXX=CC
|
||||
CXXFLAGS="-noex $STD"
|
||||
LIBS=-lmtmalloc
|
||||
./configure \
|
||||
--prefix=/usr/local/mysql \
|
||||
--localstatedir=/usr/local/mysql/data \
|
||||
--libexecdir=/usr/local/mysql/bin \
|
||||
--with-extra-charsets=complex \
|
||||
--enable-thread-safe-client \
|
||||
--enable-local-infile \
|
||||
--with-zlib-dir=bundled \
|
||||
--with-big-tables \
|
||||
--with-readline \
|
||||
--with-archive-storage-engine \
|
||||
--with-named-curses=-lcurses \
|
||||
--with-big-tables \
|
||||
--with-innodb \
|
||||
--with-example-storage-engine \
|
||||
--with-blackhole-storage-engine \
|
||||
--with-federated-storage-engine \
|
||||
--with-csv-storage-engine \
|
||||
--with-ssl \
|
||||
--enable-assembler
|
||||
LDFLAGS="-lmtmalloc"
|
||||
|
||||
# Not including:
|
||||
# --with-ndbcluster
|
||||
# --with-berkeley-db
|
||||
|
||||
gmake -j4
|
||||
test $? = 0 && make test
|
||||
. "$path/FINISH.sh"
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
gmake -k clean || true
|
||||
/bin/rm -f */.deps/*.P config.cache
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
|
||||
# To compile 64 bit, add -m64 to EXTRA_64_BIT
|
||||
EXTRA_64_BIT="-m64"
|
||||
|
||||
# For "optimal" code for this computer add -fast to EXTRA. Note that
|
||||
# this causes problem with debugging the program since -fast implies
|
||||
# -xO5.
|
||||
EXTRA=""
|
||||
|
||||
#
|
||||
# The following should not need to be touched
|
||||
#
|
||||
|
||||
export CC CXX CFLAGS CXXFLAGS
|
||||
STD="-g -mt -D_FORTEC_ $EXTRA $EXTRA_64_BIT $debug_cflags"
|
||||
ASFLAGS="$EXTRA_64_BIT"
|
||||
CC=cc-5.0
|
||||
CFLAGS="-Xa -xstrconst $STD"
|
||||
CXX=CC
|
||||
CXXFLAGS="-noex $STD"
|
||||
./configure \
|
||||
--prefix=/usr/local/mysql \
|
||||
--localstatedir=/usr/local/mysql/data \
|
||||
--libexecdir=/usr/local/mysql/bin \
|
||||
--with-extra-charsets=complex \
|
||||
--enable-thread-safe-client \
|
||||
--enable-local-infile \
|
||||
--with-zlib-dir=bundled \
|
||||
--with-big-tables \
|
||||
--with-readline \
|
||||
--with-archive-storage-engine \
|
||||
--with-named-curses=-lcurses \
|
||||
--with-big-tables \
|
||||
--with-innodb \
|
||||
--with-example-storage-engine \
|
||||
--with-blackhole-storage-engine \
|
||||
--with-federated-storage-engine \
|
||||
--with-csv-storage-engine \
|
||||
--with-ssl \
|
||||
--with-debug \
|
||||
--enable-assembler
|
||||
|
||||
# Not including:
|
||||
# --with-ndbcluster
|
||||
# --with-berkeley-db
|
||||
|
||||
gmake -j4
|
||||
@@ -9,6 +9,6 @@ PATH=$PATH:/usr/ccs/bin:/usr/local/bin
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
|
||||
CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa" CXX=gcc CXXFLAGS="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g" LIBS="-lmtmalloc" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client
|
||||
CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa $EXTRA_FLAGS $EXTRA_CFLAGS" CXX=gcc CXXFLAGS="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g $EXTRA_FLAGS $EXTRA_CXXFLAGS" LIBS="-lmtmalloc" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client
|
||||
|
||||
make -j 4
|
||||
|
||||
@@ -37,7 +37,7 @@ make -k maintainer-clean || true
|
||||
path=`dirname $0`
|
||||
. "$path/autorun.sh"
|
||||
|
||||
CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS
|
||||
CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_valgrind -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_valgrind -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS
|
||||
|
||||
make -j 4
|
||||
|
||||
|
||||
11
BUILD/compile-solaris-x86-32
Executable file
11
BUILD/compile-solaris-x86-32
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
extra_flags="-D__sun -m32"
|
||||
extra_configs="$max_configs --with-libevent"
|
||||
|
||||
LDFLAGS="-lmtmalloc -R/usr/sfw/lib"
|
||||
export LDFLAGS
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
11
BUILD/compile-solaris-x86-32-debug
Executable file
11
BUILD/compile-solaris-x86-32-debug
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
extra_flags="-D__sun -m32 $debug_cflags"
|
||||
extra_configs="$max_configs --with-libevent $debug_configs"
|
||||
|
||||
LDFLAGS="-lmtmalloc -R/usr/sfw/lib"
|
||||
export LDFLAGS
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
27
BUILD/compile-solaris-x86-32-debug-forte
Executable file
27
BUILD/compile-solaris-x86-32-debug-forte
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
# Take only #define options - the others are gcc specific.
|
||||
# (real fix is for SETUP.sh not to put gcc specific options in $debug_cflags)
|
||||
DEFS=""
|
||||
for F in $debug_cflags ; do
|
||||
expr "$F" : "^-D" && DEFS="$DEFS $F"
|
||||
done
|
||||
debug_cflags="-O0 -g $DEFS"
|
||||
|
||||
extra_flags="-m32 -mt -D_FORTEC_ -xbuiltin=%all -xlibmil -xlibmopt -fns=no -xprefetch=auto -xprefetch_level=3 $debug_cflags"
|
||||
extra_configs="$max_configs --with-libevent $debug_configs"
|
||||
|
||||
warnings=""
|
||||
c_warnings=""
|
||||
cxx_warnings=""
|
||||
base_cxxflags="-noex"
|
||||
|
||||
CC=cc
|
||||
CFLAGS="-xstrconst"
|
||||
CXX=CC
|
||||
LDFLAGS="-lmtmalloc"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
19
BUILD/compile-solaris-x86-forte-32
Executable file
19
BUILD/compile-solaris-x86-forte-32
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="-m32 -mt -D_FORTEC_ -xbuiltin=%all -xlibmil -xlibmopt -fns=no -xprefetch=auto -xprefetch_level=3"
|
||||
extra_configs="$max_configs --with-libevent"
|
||||
|
||||
warnings=""
|
||||
c_warnings=""
|
||||
cxx_warnings=""
|
||||
base_cxxflags="-noex"
|
||||
|
||||
CC=cc
|
||||
CFLAGS="-xstrconst"
|
||||
CXX=CC
|
||||
LDFLAGS="-lmtmalloc"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
48
BUILD/util.sh
Normal file
48
BUILD/util.sh
Normal file
@@ -0,0 +1,48 @@
|
||||
# MariaDB SQL server.
|
||||
# Copyright (C) 2010 Kristian Nielsen and Monty Program AB
|
||||
#
|
||||
# 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; version 2 of the License.
|
||||
#
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# Setting cpu options.
|
||||
get_cpuopt () {
|
||||
case "$(uname -o)" in
|
||||
*Linux*)
|
||||
case "$(gcc -dumpmachine)" in
|
||||
x86_64-*)
|
||||
# gcc barfs on -march=... on x64
|
||||
CPUOPT="-m64 -mtune=generic"
|
||||
;;
|
||||
*)
|
||||
# we'd use i586 to not trip up mobile/lowpower devices
|
||||
CPUOPT="-m32 -march=i586 -mtune=generic"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*Solaris*)
|
||||
# ToDo: handle 32-bit build? For now default to 64-bit.
|
||||
CPUOPT="-D__sun -m64 -mtune=athlon64"
|
||||
;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
# Default to a parallel build, but only if AM_MAKEFLAGS is not set.
|
||||
# (So buildbots can easily disable this behaviour if required.)
|
||||
get_make_parallel_flag () {
|
||||
if test -z "$AM_MAKEFLAGS"
|
||||
then
|
||||
AM_MAKEFLAGS="-j 6"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -1,8 +1,192 @@
|
||||
MariaDB and MySQL have identical install methods. In this document we
|
||||
describe how to install MariaDB; However all documentation at www.mysql.com
|
||||
also applies.
|
||||
|
||||
You can find information about how to install binary distributions at
|
||||
|
||||
http://dev.mysql.com/doc/refman/5.1/en/quick-standard-installation.html
|
||||
2.2. Installing MariaDB from Generic Binaries on Unix/Linux
|
||||
|
||||
The MySQL Reference Manual is also available in various formats on
|
||||
http://dev.mysql.com/doc; if you're interested in the DocBook XML
|
||||
sources go to http://svn.mysql.com.
|
||||
This section covers the installation of MariaDB binary distributions
|
||||
that are provided for various platforms in the form of compressed
|
||||
tar files (files with a .tar.gz extension).
|
||||
|
||||
MariaDB tar file binary distributions have names of the form
|
||||
mariadb-VERSION-OS.tar.gz, where VERSION is a number (for example,
|
||||
5.1.39), and OS indicates the type of operating system for which
|
||||
the distribution is intended (for example, pc-linux-i686).
|
||||
|
||||
You need the following tools to install a MariaDB tar file binary
|
||||
distribution:
|
||||
|
||||
* GNU gunzip to uncompress the distribution.
|
||||
|
||||
* A reasonable tar to unpack the distribution. GNU tar is known
|
||||
to work. Some operating systems come with a preinstalled
|
||||
version of tar that is known to have problems. For example,
|
||||
the tar provided with early versions of Mac OS X, SunOS 4.x,
|
||||
Solaris 8, Solaris 9, Solaris 10 and OpenSolaris, and HP-UX
|
||||
are known to have problems with long file names. On Mac OS X,
|
||||
you can use the preinstalled gnutar program. On Solaris 10 and
|
||||
OpenSolaris you can use the preinstalled gtar. On other
|
||||
systems with a deficient tar, you should install GNU tar
|
||||
first.
|
||||
|
||||
If you run into problems and need to file a bug report,
|
||||
please report them to: http://bugs.launchpad.net/maria
|
||||
|
||||
See the instructions in Section 1.6, "How to Report Bugs or Problems."
|
||||
|
||||
The basic commands that you must execute to install and use a
|
||||
MariaDB binary distribution are:
|
||||
|
||||
shell> groupadd mysql
|
||||
shell> useradd -g mysql mysql
|
||||
shell> cd /usr/local
|
||||
shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
|
||||
shell> ln -s full-path-to-mysql-VERSION-OS mysql
|
||||
shell> cd mysql
|
||||
shell> chown -R mysql .
|
||||
shell> chgrp -R mysql .
|
||||
shell> scripts/mysql_install_db --user=mysql
|
||||
shell> chown -R root .
|
||||
shell> chown -R mysql data
|
||||
shell> bin/mysqld_safe --user=mysql &
|
||||
|
||||
Note
|
||||
|
||||
This procedure does not set up any passwords for MariaDB accounts.
|
||||
After following the procedure, proceed to Section 2.13,
|
||||
"Post-Installation Setup and Testing."
|
||||
|
||||
A more detailed version of the preceding description for
|
||||
installing a binary distribution follows:
|
||||
|
||||
1. Add a login user and group for mysqld to run as:
|
||||
shell> groupadd mysql
|
||||
shell> useradd -g mysql mysql
|
||||
These commands add the mysql group and the mysql user. The
|
||||
syntax for useradd and groupadd may differ slightly on
|
||||
different versions of Unix, or they may have different names
|
||||
such as adduser and addgroup.
|
||||
You might want to call the user and group something else
|
||||
instead of mysql. If so, substitute the appropriate name in
|
||||
the following steps.
|
||||
|
||||
2. Pick the directory under which you want to unpack the
|
||||
distribution and change location into it. In the following
|
||||
example, we unpack the distribution under /usr/local. (The
|
||||
instructions, therefore, assume that you have permission to
|
||||
create files and directories in /usr/local. If that directory
|
||||
is protected, you must perform the installation as root.)
|
||||
shell> cd /usr/local
|
||||
|
||||
3. Obtain a distribution file using the instructions in Section
|
||||
2.1.3, "How to Get MariaDB." For a given release, binary
|
||||
distributions for all platforms are built from the same MariaDB
|
||||
source distribution.
|
||||
|
||||
4. Unpack the distribution, which creates the installation
|
||||
directory. Then create a symbolic link to that directory:
|
||||
shell> gunzip < /path/to/mysql-VERSION-OS.tar.gz | tar xvf -
|
||||
shell> ln -s full-path-to-mysql-VERSION-OS mysql
|
||||
The tar command creates a directory named mysql-VERSION-OS.
|
||||
The ln command makes a symbolic link to that directory. This
|
||||
lets you refer more easily to the installation directory as
|
||||
/usr/local/mysql.
|
||||
With GNU tar, no separate invocation of gunzip is necessary.
|
||||
You can replace the first line with the following alternative
|
||||
command to uncompress and extract the distribution:
|
||||
shell> tar zxvf /path/to/mysql-VERSION-OS.tar.gz
|
||||
|
||||
5. Change location into the installation directory:
|
||||
shell> cd mysql
|
||||
You will find several files and subdirectories in the mysql
|
||||
directory. The most important for installation purposes are
|
||||
the bin and scripts subdirectories:
|
||||
|
||||
+ The bin directory contains client programs and the
|
||||
server. You should add the full path name of this
|
||||
directory to your PATH environment variable so that your
|
||||
shell finds the MariaDB programs properly. See Section
|
||||
2.14, "Environment Variables."
|
||||
|
||||
+ The scripts directory contains the mysql_install_db
|
||||
script used to initialize the mysql database containing
|
||||
the grant tables that store the server access
|
||||
permissions.
|
||||
|
||||
6. Ensure that the distribution contents are accessible to mysql.
|
||||
If you unpacked the distribution as mysql, no further action
|
||||
is required. If you unpacked the distribution as root, its
|
||||
contents will be owned by root. Change its ownership to mysql
|
||||
by executing the following commands as root in the
|
||||
installation directory:
|
||||
shell> chown -R mysql .
|
||||
shell> chgrp -R mysql .
|
||||
The first command changes the owner attribute of the files to
|
||||
the mysql user. The second changes the group attribute to the
|
||||
mysql group.
|
||||
|
||||
7. If you have not installed MariaDB before, you must create the
|
||||
MariaDB data directory and initialize the grant tables:
|
||||
shell> scripts/mysql_install_db --user=mysql
|
||||
If you run the command as root, include the --user option as
|
||||
shown. If you run the command while logged in as that user,
|
||||
you can omit the --user option.
|
||||
The command should create the data directory and its contents
|
||||
with mysql as the owner.
|
||||
After creating or updating the grant tables, you need to
|
||||
restart the server manually.
|
||||
|
||||
8. Most of the MariaDB installation can be owned by root if you
|
||||
like. The exception is that the data directory must be owned
|
||||
by mysql. To accomplish this, run the following commands as
|
||||
root in the installation directory:
|
||||
|
||||
shell> chown -R root .
|
||||
shell> chown -R mysql data
|
||||
|
||||
9. If you want MariaDB to start automatically when you boot your
|
||||
machine, you can copy support-files/mysql.server to the
|
||||
location where your system has its startup files. More
|
||||
information can be found in the support-files/mysql.server
|
||||
script itself and in Section 2.13.1.2, "Starting and Stopping
|
||||
MariaDB Automatically."
|
||||
10. You can set up new accounts using the bin/mysql_setpermission
|
||||
script if you install the DBI and DBD::mysql Perl modules. See
|
||||
Section 4.6.14, "mysql_setpermission --- Interactively Set
|
||||
Permissions in Grant Tables." For Perl module installation
|
||||
instructions, see Section 2.15, "Perl Installation Notes."
|
||||
11. If you would like to use mysqlaccess and have the MariaDB
|
||||
distribution in some nonstandard location, you must change the
|
||||
location where mysqlaccess expects to find the mysql client.
|
||||
Edit the bin/mysqlaccess script at approximately line 18.
|
||||
Search for a line that looks like this:
|
||||
$MYSQL = '/usr/local/bin/mysql'; # path to mysql executable
|
||||
Change the path to reflect the location where mysql actually
|
||||
is stored on your system. If you do not do this, a Broken pipe
|
||||
error will occur when you run mysqlaccess.
|
||||
|
||||
After everything has been unpacked and installed, you should test
|
||||
your distribution. To start the MariaDB server, use the following
|
||||
command:
|
||||
shell> bin/mysqld_safe --user=mysql &
|
||||
|
||||
If you run the command as root, you must use the --user option as
|
||||
shown. The value of the option is the name of the login account
|
||||
that you created in the first step to use for running the server.
|
||||
If you run the command while logged in as mysql, you can omit the
|
||||
--user option.
|
||||
|
||||
If the command fails immediately and prints mysqld ended, you can
|
||||
find some information in the host_name.err file in the data
|
||||
directory.
|
||||
|
||||
More information about mysqld_safe is given in Section 4.3.2,
|
||||
"mysqld_safe --- MySQL Server Startup Script."
|
||||
|
||||
Note
|
||||
|
||||
The accounts that are listed in the MariaDB grant tables initially
|
||||
have no passwords. After starting the server, you should set up
|
||||
passwords for them using the instructions in Section 2.13,
|
||||
"Post-Installation Setup and Testing."
|
||||
|
||||
@@ -868,7 +868,7 @@ Space compression makes the index file smaller if the string column has a lot of
|
||||
Prefix compression helps if there are many strings with an identical prefix.
|
||||
|
||||
In memory table characteristics
|
||||
HEAP tables only exists in memory so they are lost if `mysqld' is taken down or crashes. But since they are *very* fast they are usefull as anyway.
|
||||
HEAP tables only exists in memory so they are lost if `mysqld' is taken down or crashes. But since they are *very* fast they are useful as anyway.
|
||||
|
||||
The *MySQL* internal HEAP tables uses 100% dynamic hashing without overflow areas and don't have problems with delete.
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
MariaDB is in most aspects identical to MySQL.
|
||||
|
||||
Differences between MySQL and MariaDB can be found at:
|
||||
http://askmonty.org/wiki/index.php/MariaDB_versus_MySQL
|
||||
|
||||
The MariaDB references manual can be found at:
|
||||
http://askmonty.org/wiki/index.php/Manual
|
||||
|
||||
The MySQL Reference Manual is available in various formats on
|
||||
http://dev.mysql.com/doc; if you're interested in the DocBook XML
|
||||
|
||||
@@ -1075,7 +1075,7 @@
|
||||
'PIPES_AS_CONCAT',
|
||||
'ANSI_QUOTES',
|
||||
'IGNORE_SPACE',
|
||||
'NOT_USED',
|
||||
'IGNORE_BAD_TABLE_OPTIONS',
|
||||
'ONLY_FULL_GROUP_BY',
|
||||
'NO_UNSIGNED_SUBTRACTION',
|
||||
'NO_DIR_IN_CREATE',
|
||||
|
||||
8245
INSTALL-SOURCE
8245
INSTALL-SOURCE
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,289 @@
|
||||
|
||||
You can find information about how to install from a Windows source
|
||||
distributions at
|
||||
2.5.10. Installing MySQL from Source on Windows
|
||||
|
||||
http://dev.mysql.com/doc/refman/5.1/en/windows-source-build.html
|
||||
These instructions describe how to build binaries from source for
|
||||
MySQL 5.1 on Windows. Instructions are provided for building
|
||||
binaries from a standard source distribution or from the Bazaar
|
||||
tree that contains the latest development source.
|
||||
|
||||
The MySQL Reference Manual is also available in various formats on
|
||||
http://dev.mysql.com/doc; if you're interested in the DocBook XML
|
||||
sources go to http://svn.mysql.com.
|
||||
Note
|
||||
|
||||
The instructions here are strictly for users who want to test
|
||||
MySQL on Microsoft Windows from the latest source distribution or
|
||||
from the Bazaar tree. For production use, we do not advise using a
|
||||
MySQL server built by yourself from source. Normally, it is best
|
||||
to use precompiled binary distributions of MySQL that are built
|
||||
specifically for optimal performance on Windows by Oracle
|
||||
Corporation. Instructions for installing binary distributions are
|
||||
available in Section 2.5, "Installing MySQL on Windows."
|
||||
|
||||
To build MySQL on Windows from source, you must satisfy the
|
||||
following system, compiler, and resource requirements:
|
||||
|
||||
* Windows 2000, Windows XP, or newer version.
|
||||
Windows Vista is supported when using Visual Studio 2005
|
||||
provided you have installed the following updates:
|
||||
|
||||
+ Microsoft Visual Studio 2005 Professional Edition - ENU
|
||||
Service Pack 1 (KB926601)
|
||||
(http://support.microsoft.com/?kbid=926601)
|
||||
|
||||
+ Security Update for Microsoft Visual Studio 2005
|
||||
Professional Edition - ENU (KB937061)
|
||||
(http://support.microsoft.com/?kbid=937061)
|
||||
|
||||
+ Update for Microsoft Visual Studio 2005 Professional
|
||||
Edition - ENU (KB932232)
|
||||
(http://support.microsoft.com/?kbid=932232)
|
||||
|
||||
* CMake, which can be downloaded from http://www.cmake.org.
|
||||
After installing, modify your path to include the cmake
|
||||
binary.
|
||||
|
||||
* Microsoft Visual C++ 2005 Express Edition, Visual Studio .Net
|
||||
2003 (7.1), or Visual Studio 2005 (8.0) compiler system.
|
||||
|
||||
* If you are using Visual C++ 2005 Express Edition, you must
|
||||
also install an appropriate Platform SDK. More information and
|
||||
links to downloads for various Windows platforms is available
|
||||
from
|
||||
http://www.microsoft.com/downloads/details.aspx?familyid=0baf2
|
||||
b35-c656-4969-ace8-e4c0c0716adb.
|
||||
|
||||
* If you are compiling from a Bazaar tree or making changes to
|
||||
the parser, you need bison for Windows, which can be
|
||||
downloaded from
|
||||
http://gnuwin32.sourceforge.net/packages/bison.htm. Download
|
||||
the package labeled "Complete package, excluding sources".
|
||||
After installing the package, modify your path to include the
|
||||
bison binary and ensure that this binary is accessible from
|
||||
Visual Studio.
|
||||
|
||||
* Cygwin might be necessary if you want to run the test script
|
||||
or package the compiled binaries and support files into a Zip
|
||||
archive. (Cygwin is needed only to test or package the
|
||||
distribution, not to build it.) Cygwin is available from
|
||||
http://cygwin.com.
|
||||
|
||||
* 3GB to 5GB of disk space.
|
||||
|
||||
The exact system requirements for Visual Studio can be found here:
|
||||
http://msdn.microsoft.com/vstudio/Previous/2003/sysreqs/default.as
|
||||
px and
|
||||
http://msdn.microsoft.com/vstudio/products/sysreqs/default.aspx
|
||||
|
||||
You also need a MySQL source distribution for Windows, which can
|
||||
be obtained two ways:
|
||||
|
||||
* Obtain a source distribution packaged by Oracle Corporation.
|
||||
These are available from http://dev.mysql.com/downloads/.
|
||||
|
||||
* Package a source distribution yourself from the latest Bazaar
|
||||
developer source tree. For instructions on pulling the latest
|
||||
source files, see Section 2.3.3, "Installing from the
|
||||
Development Source Tree."
|
||||
|
||||
If you find something not working as expected, or you have
|
||||
suggestions about ways to improve the current build process on
|
||||
Windows, please send a message to the win32 mailing list. See
|
||||
Section 1.6.1, "MySQL Mailing Lists."
|
||||
|
||||
2.5.10.1. Building MySQL from Source Using CMake and Visual Studio
|
||||
|
||||
You can build MySQL on Windows by using a combination of cmake and
|
||||
Microsoft Visual Studio .NET 2003 (7.1), Microsoft Visual Studio
|
||||
2005 (8.0), Microsoft Visual Studio 2008 (9.0) or Microsoft Visual
|
||||
C++ 2005 Express Edition. You must have the appropriate Microsoft
|
||||
Platform SDK installed.
|
||||
|
||||
Note
|
||||
|
||||
To compile from the source code on Windows you must use the
|
||||
standard source distribution (for example, mysql-5.1.46.tar.gz).
|
||||
You build from the same distribution as used to build MySQL on
|
||||
Unix, Linux and other platforms. Do not use the Windows Source
|
||||
distributions as they do not contain the necessary configuration
|
||||
script and other files.
|
||||
|
||||
Follow this procedure to build MySQL:
|
||||
|
||||
1. If you are installing from a packaged source distribution,
|
||||
create a work directory (for example, C:\workdir), and unpack
|
||||
the source distribution there using WinZip or another Windows
|
||||
tool that can read .zip files. This directory is the work
|
||||
directory in the following instructions.
|
||||
|
||||
Note
|
||||
You must run the commands in the win directory from the
|
||||
top-level source directory. Do not change into the win
|
||||
directory, as the commands will not be executed correctly.
|
||||
|
||||
2. Start a command shell. If you have not configured the PATH and
|
||||
other environment variables for all command shells, you may be
|
||||
able to start a command shell from the Start Menu within the
|
||||
Windows Visual Studio menu that contains the necessary
|
||||
environment changes.
|
||||
|
||||
3. Within the command shell, navigate to the work directory and
|
||||
run the following command:
|
||||
C:\workdir>win\configure.js options
|
||||
If you have associated the .js file extension with an
|
||||
application such as a text editor, then you may need to use
|
||||
the following command to force configure.js to be executed as
|
||||
a script:
|
||||
C:\workdir>cscript win\configure.js options
|
||||
These options are available for configure.js:
|
||||
|
||||
+ WITH_INNOBASE_STORAGE_ENGINE: Enable the InnoDB storage
|
||||
engine.
|
||||
|
||||
+ WITH_PARTITION_STORAGE_ENGINE: Enable user-defined
|
||||
partitioning.
|
||||
|
||||
+ WITH_ARCHIVE_STORAGE_ENGINE: Enable the ARCHIVE storage
|
||||
engine.
|
||||
|
||||
+ WITH_BLACKHOLE_STORAGE_ENGINE: Enable the BLACKHOLE
|
||||
storage engine.
|
||||
|
||||
+ WITH_EXAMPLE_STORAGE_ENGINE: Enable the EXAMPLE storage
|
||||
engine.
|
||||
|
||||
+ WITH_FEDERATED_STORAGE_ENGINE: Enable the FEDERATED
|
||||
storage engine.
|
||||
|
||||
+ WITH_NDBCLUSTER_STORAGE_ENGINE (experimental): Enable the
|
||||
NDBCLUSTER storage engine in the MySQL server; cause
|
||||
binaries for the MySQL Cluster management and data node,
|
||||
management client, and other programs to be built.
|
||||
This option is supported only in MySQL Cluster NDB 7.0
|
||||
(NDBCLUSTER storage engine versions 6.4.0 and later)
|
||||
using the MySQL Cluster sources. It cannot be used to
|
||||
enable clustering support in other MySQL source trees or
|
||||
distributions.
|
||||
|
||||
+ MYSQL_SERVER_SUFFIX=suffix: Server suffix, default none.
|
||||
|
||||
+ COMPILATION_COMMENT=comment: Server comment, default
|
||||
"Source distribution".
|
||||
|
||||
+ MYSQL_TCP_PORT=port: Server port, default 3306.
|
||||
|
||||
+ DISABLE_GRANT_OPTIONS: Disables the --bootstrap,
|
||||
--skip-grant-tables, and --init-file options for mysqld.
|
||||
This option is available as of MySQL 5.1.15.
|
||||
For example (type the command on one line):
|
||||
C:\workdir>win\configure.js WITH_INNOBASE_STORAGE_ENGINE
|
||||
WITH_PARTITION_STORAGE_ENGINE MYSQL_SERVER_SUFFIX=-pro
|
||||
|
||||
4. From the work directory, execute the win\build-vs9.bat
|
||||
(Windows Visual Studio 2008), win\build-vs8.bat (Windows
|
||||
Visual Studio 2005), or win\build-vs71.bat (Windows Visual
|
||||
Stidion 2003) script, depending on the version of Visual
|
||||
Studio you have installed. The script invokes CMake, which
|
||||
generates the mysql.sln solution file.
|
||||
You can also use the corresponding 64-bit file (for example
|
||||
win\build-vs8_x64.bat or win\build-vs9_x64.bat) to build the
|
||||
64-bit version of MySQL. However, you cannot build the 64-bit
|
||||
version with Visual Studio Express Edition. You must use
|
||||
Visual Studio 2005 (8.0) or higher.
|
||||
|
||||
5. From the work directory, open the generated mysql.sln file
|
||||
with Visual Studio and select the proper configuration using
|
||||
the Configuration menu. The menu provides Debug, Release,
|
||||
RelwithDebInfo, MinRelInfo options. Then select Solution >
|
||||
Build to build the solution.
|
||||
Remember the configuration that you use in this step. It is
|
||||
important later when you run the test script because that
|
||||
script needs to know which configuration you used.
|
||||
|
||||
6. Test the server. The server built using the preceding
|
||||
instructions expects that the MySQL base directory and data
|
||||
directory are C:\mysql and C:\mysql\data by default. If you
|
||||
want to test your server using the source tree root directory
|
||||
and its data directory as the base directory and data
|
||||
directory, you need to tell the server their path names. You
|
||||
can either do this on the command line with the --basedir and
|
||||
--datadir options, or by placing appropriate options in an
|
||||
option file. (See Section 4.2.3.3, "Using Option Files.") If
|
||||
you have an existing data directory elsewhere that you want to
|
||||
use, you can specify its path name instead.
|
||||
When the server is running in standalone fashion or as a
|
||||
service based on your configuration, try to connect to it from
|
||||
the mysql interactive command-line utility.
|
||||
You can also run the standard test script, mysql-test-run.pl.
|
||||
This script is written in Perl, so you'll need either Cygwin
|
||||
or ActiveState Perl to run it. You may also need to install
|
||||
the modules required by the script. To run the test script,
|
||||
change location into the mysql-test directory under the work
|
||||
directory, set the MTR_VS_CONFIG environment variable to the
|
||||
configuration you selected earlier (or use the --vs-config
|
||||
option), and invoke mysql-test-run.pl. For example (using
|
||||
Cygwin and the bash shell):
|
||||
shell> cd mysql-test
|
||||
shell> export MTR_VS_CONFIG=debug
|
||||
shell> ./mysql-test-run.pl --force --timer
|
||||
shell> ./mysql-test-run.pl --force --timer --ps-protocol
|
||||
|
||||
When you are satisfied that the programs you have built are
|
||||
working correctly, stop the server. Now you can install the
|
||||
distribution. One way to do this is to use the make_win_bin_dist
|
||||
script in the scripts directory of the MySQL source distribution
|
||||
(see Section 4.4.2, "make_win_bin_dist --- Package MySQL
|
||||
Distribution as ZIP Archive"). This is a shell script, so you must
|
||||
have Cygwin installed if you want to use it. It creates a Zip
|
||||
archive of the built executables and support files that you can
|
||||
unpack in the location at which you want to install MySQL.
|
||||
|
||||
It is also possible to install MySQL by copying directories and
|
||||
files directly:
|
||||
|
||||
1. Create the directories where you want to install MySQL. For
|
||||
example, to install into C:\mysql, use these commands:
|
||||
C:\> mkdir C:\mysql
|
||||
C:\> mkdir C:\mysql\bin
|
||||
C:\> mkdir C:\mysql\data
|
||||
C:\> mkdir C:\mysql\share
|
||||
C:\> mkdir C:\mysql\scripts
|
||||
If you want to compile other clients and link them to MySQL,
|
||||
you should also create several additional directories:
|
||||
C:\> mkdir C:\mysql\include
|
||||
C:\> mkdir C:\mysql\lib
|
||||
C:\> mkdir C:\mysql\lib\debug
|
||||
C:\> mkdir C:\mysql\lib\opt
|
||||
If you want to benchmark MySQL, create this directory:
|
||||
C:\> mkdir C:\mysql\sql-bench
|
||||
Benchmarking requires Perl support. See Section 2.15, "Perl
|
||||
Installation Notes."
|
||||
|
||||
2. From the work directory, copy into the C:\mysql directory the
|
||||
following files and directories:
|
||||
C:\> cd \workdir
|
||||
C:\workdir> mkdir C:\mysql
|
||||
C:\workdir> mkdir C:\mysql\bin
|
||||
C:\workdir> copy client\Release\*.exe C:\mysql\bin
|
||||
C:\workdir> copy sql\Release\mysqld.exe C:\mysql\bin\mysqld.exe
|
||||
C:\workdir> xcopy scripts\*.* C:\mysql\scripts /E
|
||||
C:\workdir> xcopy share\*.* C:\mysql\share /E
|
||||
If you want to compile other clients and link them to MySQL,
|
||||
you should also copy several libraries and header files:
|
||||
C:\workdir> copy lib\Release\mysqlclient.lib C:\mysql\lib\debug
|
||||
C:\workdir> copy lib\Release\libmysql.* C:\mysql\lib\debug
|
||||
C:\workdir> copy lib\Release\zlib.* C:\mysql\lib\debug
|
||||
C:\workdir> copy lib\Release\mysqlclient.lib C:\mysql\lib\opt
|
||||
C:\workdir> copy lib\Release\libmysql.* C:\mysql\lib\opt
|
||||
C:\workdir> copy lib\Release\zlib.* C:\mysql\lib\opt
|
||||
C:\workdir> copy include\*.h C:\mysql\include
|
||||
C:\workdir> copy libmysql\libmysql.def C:\mysql\include
|
||||
|
||||
Note
|
||||
If you have compiled a Debug, rather than Release solution,
|
||||
you can replace Release with Debug in the source file names
|
||||
shown above.
|
||||
If you want to benchmark MySQL, you should also do this:
|
||||
C:\workdir> xcopy sql-bench\*.* C:\mysql\bench /E
|
||||
|
||||
After installation, set up and start the server in the same way as
|
||||
for binary Windows distributions. This includes creating the
|
||||
system tables by running mysql_install_db. For more information,
|
||||
see Section 2.5, "Installing MySQL on Windows."
|
||||
|
||||
35
KNOWN_BUGS.txt
Normal file
35
KNOWN_BUGS.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
This file should contain all know fatal bugs in the Mariadb and the
|
||||
Maria storage engine for the last source or binary release. Minor
|
||||
bugs, extensions and feature request and bugs found since this release
|
||||
can be find in the MariaDB bugs database at:
|
||||
https://bugs.launchpad.net/maria and in the MySQL bugs databases at:
|
||||
http://bugs.mysql.com/ (category "Maria storage engine").
|
||||
|
||||
There shouldn't normally be any bugs that affects normal operations in
|
||||
any MariaDB release. Still, there are always exceptions and edge cases
|
||||
and that's what this file is for.
|
||||
|
||||
If you have found a bug that is not listed here, please add it to
|
||||
http://bugs.launchpad.net/maria so that we can either fix it for next
|
||||
release or in the worst case add it here for others to know!
|
||||
|
||||
IMPORTANT:
|
||||
|
||||
If you have been using the Maria storage engine with
|
||||
MySQL-5.1-Maria-alpha build and upgrading to a newer MariaDB you MUST
|
||||
run maria_chk --recover on all your Maria tables. This is because we
|
||||
made an incompatible change of how transaction id is stored and old
|
||||
transaction id's must be reset!
|
||||
|
||||
cd mysql-data-directory
|
||||
maria_chk --recover */*.MAI
|
||||
|
||||
As the Maria storage engine is now in beta we will do our best to not
|
||||
introduce any incompatible changes in the data format for the Maria
|
||||
tables; If this would be ever be needed, we will, if possible, support
|
||||
both the old and the new version to make upgrades as easy as possible.
|
||||
|
||||
Note that for the MariaDB 5.1 release the Maria storage engine is
|
||||
classified as 'beta'; It should work, but use it with caution. Please
|
||||
report all bugs to https://bugs.launchpad.net/maria so that we can fix
|
||||
them!
|
||||
90
Makefile.am
90
Makefile.am
@@ -55,7 +55,6 @@ bin-dist: all
|
||||
# Remove BK's "SCCS" subdirectories from source distribution
|
||||
# Create initial database files for Windows installations and check them.
|
||||
dist-hook:
|
||||
rm -rf `find $(distdir) -type d -name SCCS -print`
|
||||
mkdir -p $(distdir)/win
|
||||
scripts/mysql_install_db --no-defaults --cross-bootstrap \
|
||||
--builddir=$(top_builddir) \
|
||||
@@ -65,6 +64,11 @@ dist-hook:
|
||||
test ! -f $(top_srcdir)/configure.am || \
|
||||
$(INSTALL_DATA) $(top_srcdir)/configure.am $(distdir)
|
||||
|
||||
# Simple target to allow scripts etc. to get the name of the source
|
||||
# tarball easily.
|
||||
show-dist-name:
|
||||
@echo "$(PACKAGE)-$(VERSION)"
|
||||
|
||||
all-local: @ABI_CHECK@
|
||||
|
||||
tags:
|
||||
@@ -73,7 +77,7 @@ tags:
|
||||
.PHONY: init-db bin-dist \
|
||||
test test-force test-full test-force-full test-force-mem \
|
||||
test-pl test-force-pl test-full-pl test-force-full-pl test-force-pl-mem \
|
||||
test-unit test-ps test-nr test-pr test-ns test-binlog-statement \
|
||||
test-unit test-unit-big test-ps test-nr test-pr test-ns test-binlog-statement \
|
||||
test-ext-funcs test-ext-rpl test-ext-partitions test-ext-jp \
|
||||
test-ext-stress test-ext test-embedded test-reprepare \
|
||||
test-fast test-fast-cursor test-fast-view test-fast-prepare \
|
||||
@@ -86,36 +90,42 @@ tags:
|
||||
# environment variable MTR_BUILD_THREAD. The script "mysql-test-run"
|
||||
# will then calculate the various port numbers it needs from this,
|
||||
# making sure each user use different ports.
|
||||
#
|
||||
# Set MTR_EXTRA_OPTIONS to add custom options for mysql-test-run,
|
||||
# like MTR_EXTRA_OPTIONS"--parallel=3 --mem".
|
||||
|
||||
test-unit:
|
||||
cd unittest && $(MAKE) test
|
||||
cd unittest; $(MAKE) test
|
||||
|
||||
test-unit-big:
|
||||
cd unittest; MYTAP_CONFIG=big $(MAKE) test
|
||||
|
||||
test-ps:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) --ps-protocol --mysqld=--binlog-format=mixed
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) --ps-protocol --mysqld=--binlog-format=mixed
|
||||
|
||||
test-nr:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) --mysqld=--binlog-format=row
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) --mysqld=--binlog-format=row
|
||||
|
||||
test-pr:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) $(mem) --ps-protocol --mysqld=--binlog-format=row
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) $(mem) --ps-protocol --mysqld=--binlog-format=row #@libevent_test_option@
|
||||
|
||||
test-ns:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) $(mem) --mysqld=--binlog-format=mixed ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) $(mem) --suite=funcs_1
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) $(mem) --mysqld=--binlog-format=mixed ; \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) $(mem) --suite=funcs_1
|
||||
|
||||
test-binlog-statement:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) --mysqld=--binlog-format=statement
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) --mysqld=--binlog-format=statement
|
||||
|
||||
# This code is duplicated in "test-bt", see the Changeset comment of 2007-Dec-07
|
||||
test-embedded:
|
||||
if [ -e bin/mysqltest_embedded -o -e libmysqld/examples/mysqltest_embedded ] ; then \
|
||||
cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=embedded --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=embedded --force --timer \
|
||||
--embedded-server --skip-rpl --skip-ndbcluster ; \
|
||||
else \
|
||||
echo "no program found for 'embedded' tests - skipped testing" ; \
|
||||
@@ -123,14 +133,14 @@ test-embedded:
|
||||
|
||||
test-reprepare:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(force) $(mem) --ps-protocol \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(force) $(mem) --ps-protocol \
|
||||
--mysqld=--debug=+d,reprepare_each_statement
|
||||
|
||||
test: test-unit test-ns test-pr
|
||||
test: test-ns test-pr
|
||||
|
||||
smoke:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl --do-test=s
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --do-test=s
|
||||
|
||||
test-full: test test-nr test-ps
|
||||
|
||||
@@ -148,43 +158,45 @@ EXP = --experimental=collections/default.experimental
|
||||
|
||||
test-bt:
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=normal --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=normal --force --timer \
|
||||
--skip-ndbcluster --report-features $(EXP)
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=ps --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=ps --force --timer \
|
||||
--skip-ndbcluster --ps-protocol $(EXP)
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=PBXT --mysqld=--default-storage-engine=pbxt --suite=pbxt $(EXP)
|
||||
-if [ -e bin/ndbd -o -e storage/ndb/src/kernel/ndbd ] ; then \
|
||||
cd mysql-test ; \
|
||||
MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=ndb+ps --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=ndb+ps --force --timer \
|
||||
--ps-protocol --mysqld=--binlog-format=row --suite=ndb $(EXP) ; \
|
||||
MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=ndb --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=ndb --force --timer \
|
||||
--with-ndbcluster-only $(EXP) ; \
|
||||
else \
|
||||
echo "no program found for 'ndbcluster' tests - skipped testing" ; \
|
||||
fi
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --force --comment=funcs1+ps --ps-protocol --reorder --suite=funcs_1 $(EXP)
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=funcs1+ps --ps-protocol --reorder --suite=funcs_1 $(EXP)
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --force --comment=funcs2 --suite=funcs_2 $(EXP)
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=funcs2 --suite=funcs_2 $(EXP)
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --force --comment=partitions --suite=parts $(EXP)
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=partitions --suite=parts $(EXP)
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --force --comment=stress --suite=stress $(EXP)
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=stress --suite=stress $(EXP)
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --force --comment=jp --suite=jp $(EXP)
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=jp --suite=jp $(EXP)
|
||||
-if [ -d mysql-test/suite/nist ] ; then \
|
||||
cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=nist --force --suite=nist $(EXP) ; \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=nist --force --suite=nist $(EXP) ; \
|
||||
fi
|
||||
-if [ -d mysql-test/suite/nist ] ; then \
|
||||
cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=nist+ps --force --suite=nist --ps-protocol $(EXP) ; \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=nist+ps --force --suite=nist --ps-protocol $(EXP) ; \
|
||||
fi
|
||||
-if [ -e bin/mysqltest_embedded -o -e libmysqld/examples/mysqltest_embedded ] ; then \
|
||||
cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=embedded --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=embedded --force --timer \
|
||||
--embedded-server --skip-rpl --skip-ndbcluster $(EXP) ; \
|
||||
else \
|
||||
echo "no program found for 'embedded' tests - skipped testing" ; \
|
||||
@@ -197,17 +209,17 @@ test-bt-fast:
|
||||
-if [ -e bin/ndbd -o -e storage/ndb/src/kernel/ndbd ] ; then \
|
||||
cd mysql-test ; \
|
||||
MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=ndb --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=ndb --force --timer \
|
||||
--with-ndbcluster-only $(EXP) ; \
|
||||
else \
|
||||
echo "no program found for 'ndbcluster' tests - skipped testing" ; \
|
||||
fi
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --force --comment=stress --suite=stress $(EXP)
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=stress --suite=stress $(EXP)
|
||||
|
||||
test-bt-debug:
|
||||
-cd mysql-test ; MTR_BUILD_THREAD=auto \
|
||||
@PERL@ ./mysql-test-run.pl --comment=debug --force --timer \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=debug --force --timer \
|
||||
--skip-ndbcluster --skip-rpl --report-features $(EXP)
|
||||
|
||||
# Keep these for a while
|
||||
@@ -219,32 +231,32 @@ test-force-full-pl: test-force-full
|
||||
|
||||
test-ext-funcs:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl --force --reorder --suite=funcs_1 ; \
|
||||
@PERL@ ./mysql-test-run.pl --force --suite=funcs_2
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --reorder --suite=funcs_1 ; \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --suite=funcs_2
|
||||
|
||||
test-ext-rpl:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl --force --suite=rpl
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --suite=rpl
|
||||
|
||||
test-ext-partitions:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl --force --suite=parts
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --suite=parts
|
||||
|
||||
test-ext-jp:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl --force --suite=jp
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --suite=jp
|
||||
|
||||
test-ext-stress:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl --force --big-test --suite=stress
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --big-test --suite=stress
|
||||
|
||||
test-ext: test-ext-funcs test-ext-rpl test-ext-partitions test-ext-jp test-ext-stress
|
||||
|
||||
test-fast:
|
||||
cd mysql-test ; \
|
||||
@PERL@ ./mysql-test-run.pl $(subset) --force --skip-ndb --skip-innodb --skip-im --skip-rpl ; \
|
||||
@PERL@ ./mysql-test-run.pl $(subset) --force --suite=funcs_1 --do-test=myisam ; \
|
||||
@PERL@ ./mysql-test-run.pl $(subset) --force --suite=stress --do-test=ddl_myisam
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(subset) --force --skip-ndb --skip-innodb --skip-im --skip-rpl ; \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(subset) --force --suite=funcs_1 --do-test=myisam ; \
|
||||
@PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) $(subset) --force --suite=stress --do-test=ddl_myisam
|
||||
|
||||
test-fast-view:
|
||||
$(MAKE) subset=--view-protocol test-fast
|
||||
@@ -256,7 +268,7 @@ test-fast-prepare:
|
||||
$(MAKE) subset=--ps-protocol test-fast
|
||||
|
||||
test-full-qa:
|
||||
$(MAKE) force=--force test-pr \
|
||||
$(MAKE) -k force=--force test-pr \
|
||||
test-binlog-statement test-ext test-fast-view \
|
||||
test-fast-cursor test-unit
|
||||
|
||||
@@ -266,6 +278,8 @@ test-full-qa:
|
||||
|
||||
API_PREPROCESSOR_HEADER = $(top_srcdir)/include/mysql/plugin_audit.h \
|
||||
$(top_srcdir)/include/mysql/plugin_ftparser.h \
|
||||
$(top_srcdir)/include/mysql/plugin_auth.h \
|
||||
$(top_srcdir)/include/mysql/client_plugin.h \
|
||||
$(top_srcdir)/include/mysql.h \
|
||||
$(top_srcdir)/include/mysql/psi/psi_abi_v1.h \
|
||||
$(top_srcdir)/include/mysql/psi/psi_abi_v2.h
|
||||
|
||||
308
README
308
README
@@ -1,54 +1,49 @@
|
||||
This is a release of MySQL, a dual-license SQL DBMS.
|
||||
MySQL is brought to you by the MySQL team at Oracle Corporation.
|
||||
This is a release of MariaDB.
|
||||
|
||||
MariaDB is designed as a drop-in replacement of MySQL(R) with more
|
||||
features, new storage engines, fewer bugs, and better performance.
|
||||
|
||||
MariaDB is brought to you by many of the original developers of MySQL
|
||||
who now work for Monty Program Ab, and by many people in the
|
||||
community.
|
||||
|
||||
MySQL, which is the base of MariaDB, is a product and trademark of Sun
|
||||
Microsystems, Inc. For a list of developers and other contributors,
|
||||
see the Credits appendix. You can also do 'SHOW authors' to get a
|
||||
list of active contributors.
|
||||
|
||||
A description of the MariaDB project and a manual can be found at:
|
||||
http://askmonty.org/wiki/index.php/MariaDB
|
||||
http://askmonty.org/wiki/index.php/MariaDB_versus_MySQL
|
||||
http://askmonty.org/wiki/index.php/Manual:Contents
|
||||
|
||||
As MariaDB is a full replacement of MySQL, the MySQL manual at
|
||||
http://dev.mysql.com/doc is generally applicable.
|
||||
|
||||
More help is available from the Maria Discuss mailing list
|
||||
https://launchpad.net/~maria-discuss
|
||||
and the #maria IRC channel on Freenode.
|
||||
|
||||
***********************************************************
|
||||
|
||||
NOTE:
|
||||
|
||||
MariaDB is specifically available only under version 2 of the GNU
|
||||
General Public License (GPLv2). (I.e. Without the "any later version"
|
||||
clause.) This is inherited from MySQL. Please see the README file in
|
||||
the MySQL distribution for more information.
|
||||
|
||||
License information can be found in the COPYING file and the
|
||||
EXCEPTIONS-CLIENT file.
|
||||
|
||||
************************************************************
|
||||
LICENSE
|
||||
************************************************************
|
||||
License information and use restrictions of this software can
|
||||
be found in these files:
|
||||
- For GPL (free) distributions, see the COPYING file and
|
||||
the EXCEPTIONS-CLIENT file.
|
||||
- For commercial distributions, see the LICENSE.mysql file.
|
||||
|
||||
GPLv2 Disclaimer
|
||||
For the avoidance of doubt, except that if any license choice
|
||||
other than GPL or LGPL is available it will apply instead, Oracle
|
||||
elects to use only the General Public License version 2 (GPLv2)
|
||||
at this time for any software where a choice of GPL license versions
|
||||
is made available with the language indicating that GPLv2 or any
|
||||
later version may be used, or where a choice of which version of
|
||||
the GPL is applied is otherwise unspecified.
|
||||
|
||||
************************************************************
|
||||
FURTHER INFORMATION
|
||||
************************************************************
|
||||
For further information about MySQL or additional documentation, see:
|
||||
- The latest information about MySQL: http://dev.mysql.com/
|
||||
- The current MySQL documentation: http://dev.mysql.com/doc/
|
||||
|
||||
Some manual sections of special interest:
|
||||
- If you are migrating from an older version of MySQL, please read
|
||||
the "Upgrading from..." section first!
|
||||
- To see what MySQL can do, take a look at the features section.
|
||||
- For installation instructions, see the Installing and Upgrading
|
||||
chapter.
|
||||
- For the new features/bugfix history, see the Change History appendix.
|
||||
- For the currently known bugs/misfeatures (known errors) see the
|
||||
Problems and Common Errors appendix.
|
||||
- For a list of developers and other contributors, see the Credits
|
||||
appendix.
|
||||
|
||||
A local copy of the MySQL Reference Manual can be found in the Docs
|
||||
directory in GNU Info format. You can also browse the manual online or
|
||||
download it in any of several formats at the URL given earlier in this
|
||||
file.
|
||||
|
||||
************************************************************
|
||||
IMPORTANT:
|
||||
|
||||
Bug or error reports should be sent to http://bugs.mysql.com.
|
||||
************************************************************
|
||||
Bug and/or error reports regarding MariaDB should be submitted at
|
||||
https://bugs.launchpad.net/maria
|
||||
|
||||
Bugs in the MySQL code can also be submitted at http://bugs.mysql.com
|
||||
|
||||
************************************************************
|
||||
THIRD-PARTY SOFTWARE
|
||||
@@ -188,20 +183,16 @@ cmake-2.4.8/Utilities/cmtar/compat/gethostname.c:
|
||||
|
||||
**************************************************************************
|
||||
|
||||
* Author : Per Foreby, perf@efd.lth.se
|
||||
* Author : Juergen Pfeifer, juergen.pfeifer@gmx.net
|
||||
*
|
||||
Author : Per Foreby, perf@efd.lth.se
|
||||
*
|
||||
Author : Juergen Pfeifer, juergen.pfeifer@gmx.net
|
||||
*
|
||||
|
||||
*
|
||||
**************************************************************************
|
||||
|
||||
----------------------------------------
|
||||
|
||||
Copyright (c) 2002 Insight Consortium. All rights reserved.
|
||||
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for
|
||||
details.
|
||||
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
|
||||
|
||||
This software is distributed WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
@@ -210,9 +201,7 @@ details.
|
||||
--------------------------------------------
|
||||
|
||||
Skeleton parser for Yacc-like parsing with Bison,
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free
|
||||
Software Foundati
|
||||
on, Inc.
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 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
|
||||
@@ -254,11 +243,9 @@ cmake-2.4.8/Utilities/cmzlib/zlib.h:
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must
|
||||
not be
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jean-loup Gailly Mark Adler
|
||||
|
||||
@@ -269,19 +256,15 @@ distribution.
|
||||
use in Curl. His latest changes were done 2000-09-18.
|
||||
|
||||
It has since been patched away like a madman by Daniel Stenberg
|
||||
to make it better applied to curl conditions, and to
|
||||
make
|
||||
it not use globals, pollute name space and more. This source code
|
||||
awaits a
|
||||
to make it better applied to curl conditions, and to make
|
||||
it not use globals, pollute name space and more. This source code awaits a
|
||||
rewrite to work around the paragraph 2 in the BSD licenses as explained
|
||||
below.
|
||||
|
||||
Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Hgskolan
|
||||
It has since been patched and modified a lot by Daniel Stenberg
|
||||
to make it better applied to curl conditions, and to
|
||||
make
|
||||
it not use globals, pollute name space and more. This source code
|
||||
awaits a
|
||||
to make it better applied to curl conditions, and to make
|
||||
it not use globals, pollute name space and more. This source code awaits a
|
||||
rewrite to work around the paragraph 2 in the BSD licenses as explained
|
||||
below.
|
||||
|
||||
@@ -306,19 +289,15 @@ awaits a
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE OR CONTRIBUTORS BE
|
||||
LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE 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
|
||||
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.
|
||||
SUCH DAMAGE.
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
@@ -334,8 +313,7 @@ STRICT
|
||||
--------------------------------------------------
|
||||
|
||||
cmake-2.4.8/Utilities/cmcurl/inet_pton.c,
|
||||
cmake-2.4.8/Source/CTest/Curl/inet_pto
|
||||
n.c:
|
||||
cmake-2.4.8/Source/CTest/Curl/inet_pton.c:
|
||||
This is from the BIND 4.9.4 release, modified to compile by itself
|
||||
|
||||
Copyright (c) 1996 by Internet Software Consortium.
|
||||
@@ -344,16 +322,13 @@ n.c:
|
||||
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 INTERNET SOFTWARE CONSORTIUM
|
||||
DISCLAIMS
|
||||
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
WARRANTIES
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
CONSORTIUM 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
|
||||
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
||||
|
||||
-------------------------------------------------------
|
||||
@@ -371,24 +346,19 @@ OF THIS
|
||||
* 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.
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL
|
||||
* 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
|
||||
* 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.
|
||||
* SUCH DAMAGE.
|
||||
|
||||
---------------------------------------------------
|
||||
|
||||
@@ -443,15 +413,12 @@ ANY WAY
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
@@ -480,61 +447,34 @@ STRICT
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
***************************************************************************
|
||||
Copyright (c) 1998 Free Software Foundation, Inc.
|
||||
****************************************************************************
|
||||
Copyright (c) 1998 Free Software Foundation, Inc. *
|
||||
Copyright (c) 1998,2000 Free Software Foundation, Inc. *
|
||||
*
|
||||
Copyright (c) 1998,2000 Free Software Foundation, 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, distribute with modifications, 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. *
|
||||
*
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a *
|
||||
copy of this software and associated documentation files (the
|
||||
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 ABOVE 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. *
|
||||
*
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
*
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
*
|
||||
distribute, distribute with modifications, 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 ABOVE 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.
|
||||
*
|
||||
|
||||
*
|
||||
|
||||
*
|
||||
Except as contained in this notice, the name(s) of the above
|
||||
copyright *
|
||||
holders shall not be used in advertising or otherwise to promote the
|
||||
*
|
||||
sale, use or other dealings in this Software without prior written
|
||||
*
|
||||
authorization.
|
||||
*
|
||||
Except as contained in this notice, the name(s) of the above copyright *
|
||||
holders shall not be used in advertising or otherwise to promote the *
|
||||
sale, use or other dealings in this Software without prior written *
|
||||
authorization. *
|
||||
***************************************************************************
|
||||
|
||||
------------------------------------------------------
|
||||
@@ -553,14 +493,12 @@ copyright *
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES,
|
||||
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS;
|
||||
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
|
||||
@@ -568,15 +506,12 @@ PROFITS;
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL
|
||||
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
|
||||
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.
|
||||
@@ -616,36 +551,6 @@ Use of any of this software is governed by the terms of the license below:
|
||||
|
||||
***************************************************************************
|
||||
|
||||
%%The following software may be included in this product:
|
||||
dbug_analyze.c (part of Fred Fish's Dbug Library)
|
||||
|
||||
Use of any of this software is governed by the terms of the license below:
|
||||
|
||||
* *
|
||||
* Copyright Abandoned, 1987, Fred Fish *
|
||||
* *
|
||||
* *
|
||||
* This previously copyrighted work has been placed into the public *
|
||||
* domain by the author and may be freely used for any purpose, *
|
||||
* private or commercial. *
|
||||
* *
|
||||
* Because of the number of inquiries I was receiving about the use *
|
||||
* of this product in commercially developed works I have decided to *
|
||||
* simply make it public domain to further its unrestricted use. I *
|
||||
* specifically would be most happy to see this material become a *
|
||||
* part of the standard Unix distributions by AT&T and the Berkeley *
|
||||
* Computer Science Research Group, and a standard part of the GNU *
|
||||
* system from the Free Software Foundation. *
|
||||
* *
|
||||
* I would appreciate it, as a courtesy, if this notice is left in *
|
||||
* all copies and derivative works. Thank you. *
|
||||
* *
|
||||
* The author makes no warranty of any kind with respect to this *
|
||||
* product and explicitly disclaims any implied warranties of mer- *
|
||||
* chantability or fitness for any particular purpose.
|
||||
|
||||
***************************************************************************
|
||||
|
||||
%%The following software may be included in this product:
|
||||
GNU Libtool, only ltmain.sh, libtool, auto-gen fil
|
||||
|
||||
@@ -1187,8 +1092,7 @@ Use of any of this software is governed by the terms of the license below:
|
||||
* Copyright (c) 2000 Dug Song
|
||||
*
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights
|
||||
reserved.
|
||||
* 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
|
||||
@@ -1456,10 +1360,8 @@ text:
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place -
|
||||
Suite 330,
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
@@ -1624,7 +1526,7 @@ products and corporate names mentioned herein which are trademarks of a third
|
||||
party are used only for explanation and for the owners' benefit and with no
|
||||
intent to infringe.
|
||||
3. Use of third party products or information referred to herein is
|
||||
at the user’s risk.
|
||||
at the user's risk.
|
||||
6. Miscellaneous.
|
||||
1. Jurisdiction and Venue. This server is operated from a location
|
||||
in the State of California, United States of America. Unicode makes no
|
||||
@@ -1639,10 +1541,10 @@ California. The user agrees said courts have personal jurisdiction and agree to
|
||||
waive any right to transfer the dispute to any other forum.
|
||||
2. Modification by Unicode Unicode shall have the right to modify
|
||||
this Agreement at any time by posting it to this site. The user may not assign
|
||||
any part of this Agreement without Unicode’s prior written consent.
|
||||
any part of this Agreement without Unicode's prior written consent.
|
||||
3. Taxes. The user agrees to pay any taxes arising from access to
|
||||
this website or use of the information herein, except for those based on
|
||||
Unicode’s net income.
|
||||
Unicode's net income.
|
||||
4. Severability. If any provision of this Agreement is declared
|
||||
invalid or unenforceable, the remaining provisions of this Agreement shall
|
||||
remain in effect.
|
||||
@@ -2266,8 +2168,7 @@ See
|
||||
http://src.opensolaris.org/source/xref//sfw/usr/src/cmd/gdb/gdb-6.3/include/ieee.h
|
||||
|
||||
|
||||
/* IEEE Standard 695-1980 "Universal Format for Object Modules"
|
||||
header file
|
||||
/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file
|
||||
Contributed by Cygnus Support. */
|
||||
|
||||
***************************************************************************
|
||||
@@ -2297,8 +2198,7 @@ Use of any of this software is governed by the terms of the license below:
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
***************************************************************************
|
||||
|
||||
@@ -72,3 +72,7 @@ ENDIF(WIN32)
|
||||
SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap
|
||||
PROPERTIES HAS_CXX TRUE)
|
||||
|
||||
ADD_DEFINITIONS(-DHAVE_DLOPEN)
|
||||
|
||||
INSTALL(TARGETS mysql mysqltest mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow
|
||||
mysqlbinlog mysqladmin mysqlslap echo DESTINATION bin COMPONENT runtime)
|
||||
|
||||
@@ -99,8 +99,8 @@ mysql_upgrade_SOURCES= mysql_upgrade.c \
|
||||
|
||||
# Fix for mit-threads
|
||||
DEFS = -DMYSQL_CLIENT_NO_THREADS \
|
||||
-DDEFAULT_MYSQL_HOME="\"$(prefix)\"" \
|
||||
-DMYSQL_DATADIR="\"$(localstatedir)\""
|
||||
-DDEFAULT_MYSQL_HOME='"$(prefix)"' \
|
||||
-DMYSQL_DATADIR='"$(localstatedir)"'
|
||||
|
||||
sql_src=log_event.h sql_priv.h rpl_constants.h \
|
||||
rpl_tblmap.h rpl_tblmap.cc \
|
||||
@@ -108,7 +108,8 @@ sql_src=log_event.h sql_priv.h rpl_constants.h \
|
||||
log_event_old.h log_event_old.cc \
|
||||
rpl_record_old.h rpl_record_old.cc \
|
||||
rpl_utility.h rpl_utility.cc \
|
||||
transaction.h sql_const.h
|
||||
transaction.h sql_const.h \
|
||||
sql_list.h rpl_filter.h sql_list.cc rpl_filter.cc
|
||||
strings_src=decimal.c dtoa.c
|
||||
|
||||
link_sources:
|
||||
|
||||
@@ -84,7 +84,11 @@ enum options_client
|
||||
OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE,
|
||||
OPT_WRITE_BINLOG, OPT_DUMP_DATE,
|
||||
OPT_INIT_COMMAND,
|
||||
OPT_MAX_CLIENT_OPTION
|
||||
OPT_ABORT_SOURCE_ON_ERROR,
|
||||
OPT_REWRITE_DB,
|
||||
OPT_PLUGIN_DIR,
|
||||
OPT_DEFAULT_PLUGIN,
|
||||
OPT_MAX_CLIENT_OPTION /* should be always the last */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -113,7 +113,7 @@ static void get_password(char *to,uint length,int fd, my_bool echo)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char tmp;
|
||||
uchar tmp;
|
||||
if (my_read(fd,&tmp,1,MYF(0)) != 1)
|
||||
break;
|
||||
if (tmp == '\b' || (int) tmp == 127)
|
||||
@@ -138,7 +138,7 @@ static void get_password(char *to,uint length,int fd, my_bool echo)
|
||||
fputc('*',stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
*(pos++) = tmp;
|
||||
*(pos++)= (char) tmp;
|
||||
}
|
||||
while (pos != to && isspace(pos[-1]) == ' ')
|
||||
pos--; /* Allow dummy space at end */
|
||||
|
||||
199
client/mysql.cc
199
client/mysql.cc
@@ -1,4 +1,6 @@
|
||||
/* Copyright 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
/* Copyright (C) 2000-2009 MySQL AB
|
||||
Copyright 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright 2000-2010 Monty Program Ab
|
||||
|
||||
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
|
||||
@@ -14,7 +16,6 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#define COPYRIGHT_NOTICE "\
|
||||
Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.\n\
|
||||
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
|
||||
and you are welcome to modify and redistribute it under the GPL v2 license\n"
|
||||
|
||||
@@ -48,7 +49,7 @@ and you are welcome to modify and redistribute it under the GPL v2 license\n"
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
const char *VER= "14.14";
|
||||
const char *VER= "14.16";
|
||||
|
||||
/* Don't try to make a nice table if the data is too big */
|
||||
#define MAX_COLUMN_LENGTH 1024
|
||||
@@ -86,8 +87,9 @@ extern "C" {
|
||||
#include <term.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif /* defined(HAVE_CURSES_H) && defined(HAVE_TERM_H) */
|
||||
|
||||
#undef bcmp // Fix problem with new readline
|
||||
#if defined(__WIN__)
|
||||
#include <conio.h>
|
||||
#else
|
||||
@@ -95,7 +97,6 @@ extern "C" {
|
||||
#define HAVE_READLINE
|
||||
#define USE_POPEN
|
||||
#endif
|
||||
//int vidattr(long unsigned int attrs); // Was missing in sun curses
|
||||
}
|
||||
|
||||
#if !defined(HAVE_VIDATTR)
|
||||
@@ -143,16 +144,18 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0,
|
||||
opt_secure_auth= 0,
|
||||
default_pager_set= 0, opt_sigint_ignore= 0,
|
||||
auto_vertical_output= 0,
|
||||
show_warnings= 0, executing_query= 0, interrupted_query= 0,
|
||||
show_warnings= 0, executing_query= 0,
|
||||
ignore_spaces= 0;
|
||||
static my_bool debug_info_flag, debug_check_flag;
|
||||
static my_bool debug_info_flag, debug_check_flag, batch_abort_on_error;
|
||||
static my_bool column_types_flag;
|
||||
static my_bool preserve_comments= 0;
|
||||
static my_bool in_com_source, aborted= 0;
|
||||
static ulong opt_max_allowed_packet, opt_net_buffer_length;
|
||||
static uint verbose=0,opt_silent=0,opt_mysql_port=0, opt_local_infile=0;
|
||||
static uint my_end_arg;
|
||||
static char * opt_mysql_unix_port=0;
|
||||
static int connect_flag=CLIENT_INTERACTIVE;
|
||||
static int interrupted_query= 0;
|
||||
static char *current_host,*current_db,*current_user=0,*opt_password=0,
|
||||
*current_prompt=0, *delimiter_str= 0,
|
||||
*default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME,
|
||||
@@ -166,6 +169,7 @@ static int wait_time = 5;
|
||||
static STATUS status;
|
||||
static ulong select_limit,max_join_size,opt_connect_timeout=0;
|
||||
static char mysql_charsets_dir[FN_REFLEN+1];
|
||||
static char *opt_plugin_dir= 0, *opt_default_auth;
|
||||
static const char *xmlmeta[] = {
|
||||
"&", "&",
|
||||
"<", "<",
|
||||
@@ -1022,7 +1026,7 @@ static const char *load_default_groups[]= { "mysql","client",0 };
|
||||
static int embedded_server_arg_count= 0;
|
||||
static char *embedded_server_args[MAX_SERVER_ARGS];
|
||||
static const char *embedded_server_groups[]=
|
||||
{ "server", "embedded", "mysql_SERVER", 0 };
|
||||
{ "server", "embedded", "mysql_SERVER", "mariadb_SERVER", 0 };
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
/*
|
||||
@@ -1078,9 +1082,10 @@ int main(int argc,char *argv[])
|
||||
delimiter_str= delimiter;
|
||||
default_prompt = my_strdup(getenv("MYSQL_PS1") ?
|
||||
getenv("MYSQL_PS1") :
|
||||
"mysql> ",MYF(MY_WME));
|
||||
"\\N [\\d]> ",MYF(MY_WME));
|
||||
current_prompt = my_strdup(default_prompt,MYF(MY_WME));
|
||||
prompt_counter=0;
|
||||
aborted= 0;
|
||||
|
||||
outfile[0]=0; // no (default) outfile
|
||||
strmov(pager, "stdout"); // the default, if --pager wasn't given
|
||||
@@ -1169,10 +1174,11 @@ int main(int argc,char *argv[])
|
||||
window_resize(0);
|
||||
#endif
|
||||
|
||||
put_info("Welcome to the MySQL monitor. Commands end with ; or \\g.",
|
||||
put_info("Welcome to the MariaDB monitor. Commands end with ; or \\g.",
|
||||
INFO_INFO);
|
||||
sprintf((char*) glob_buffer.ptr(),
|
||||
"Your MySQL connection id is %lu\nServer version: %s\n",
|
||||
"Your %s connection id is %lu\nServer version: %s\n",
|
||||
mysql_get_server_name(&mysql),
|
||||
mysql_thread_id(&mysql), server_version_string(&mysql));
|
||||
put_info((char*) glob_buffer.ptr(),INFO_INFO);
|
||||
|
||||
@@ -1285,14 +1291,15 @@ sig_handler mysql_end(int sig)
|
||||
/*
|
||||
This function handles sigint calls
|
||||
If query is in process, kill query
|
||||
If 'source' is executed, abort source command
|
||||
no query in process, terminate like previous behavior
|
||||
*/
|
||||
|
||||
sig_handler handle_sigint(int sig)
|
||||
{
|
||||
char kill_buffer[40];
|
||||
MYSQL *kill_mysql= NULL;
|
||||
|
||||
/* terminate if no query being executed, or we already tried interrupting */
|
||||
/* terminate if no query being executed, or we already tried interrupting */
|
||||
if (!executing_query || (interrupted_query == 2))
|
||||
{
|
||||
@@ -1308,6 +1315,7 @@ sig_handler handle_sigint(int sig)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* First time try to kill the query, second time the connection */
|
||||
interrupted_query++;
|
||||
|
||||
/* mysqld < 5 does not understand KILL QUERY, skip to KILL CONNECTION */
|
||||
@@ -1318,11 +1326,15 @@ sig_handler handle_sigint(int sig)
|
||||
sprintf(kill_buffer, "KILL %s%lu",
|
||||
(interrupted_query == 1) ? "QUERY " : "",
|
||||
mysql_thread_id(&mysql));
|
||||
tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n", kill_buffer);
|
||||
if (verbose)
|
||||
tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n",
|
||||
kill_buffer);
|
||||
mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer));
|
||||
mysql_close(kill_mysql);
|
||||
tee_fprintf(stdout, "Ctrl-C -- query aborted.\n");
|
||||
|
||||
tee_fprintf(stdout, "Ctrl-C -- query killed. Continuing normally.\n");
|
||||
interrupted_query= 0;
|
||||
if (in_com_source)
|
||||
aborted= 1; // Abort source command
|
||||
return;
|
||||
|
||||
err:
|
||||
@@ -1334,7 +1346,6 @@ err:
|
||||
handler called mysql_end().
|
||||
*/
|
||||
mysql_thread_end();
|
||||
return;
|
||||
#else
|
||||
mysql_end(sig);
|
||||
#endif
|
||||
@@ -1357,6 +1368,10 @@ static struct my_option my_long_options[] =
|
||||
0, 0, 0, 0, 0},
|
||||
{"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
|
||||
0, 0, 0, 0, 0},
|
||||
{"abort-source-on-error", OPT_ABORT_SOURCE_ON_ERROR,
|
||||
"Abort 'source filename' operations in case of errors",
|
||||
&batch_abort_on_error, &batch_abort_on_error, 0,
|
||||
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"auto-rehash", OPT_AUTO_REHASH,
|
||||
"Enable automatic rehashing. One doesn't need to use 'rehash' to get table "
|
||||
"and field completion, but startup and reconnecting may take a longer time. "
|
||||
@@ -1413,7 +1428,7 @@ static struct my_option my_long_options[] =
|
||||
{"vertical", 'E', "Print the output of a query (rows) vertically.",
|
||||
&vertical, &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
|
||||
0},
|
||||
{"force", 'f', "Continue even if we get an SQL error.",
|
||||
{"force", 'f', "Continue even if we get an SQL error. Sets abort-source-on-error to 0",
|
||||
&ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
|
||||
0, 0, 0, 0},
|
||||
{"named-commands", 'G',
|
||||
@@ -1564,6 +1579,13 @@ static struct my_option my_long_options[] =
|
||||
{"show-warnings", OPT_SHOW_WARNINGS, "Show warnings after every statement.",
|
||||
&show_warnings, &show_warnings, 0, GET_BOOL, NO_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
|
||||
(uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0,
|
||||
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"default_auth", OPT_PLUGIN_DIR,
|
||||
"Default authentication client-side plugin to use.",
|
||||
(uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0,
|
||||
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -1747,6 +1769,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
#endif
|
||||
break;
|
||||
#include <sslopt-case.h>
|
||||
case 'f':
|
||||
batch_abort_on_error= 0;
|
||||
break;
|
||||
case 'V':
|
||||
usage(1);
|
||||
exit(0);
|
||||
@@ -1830,7 +1855,7 @@ static int read_and_execute(bool interactive)
|
||||
String buffer;
|
||||
#endif
|
||||
|
||||
char *line;
|
||||
char *line= 0;
|
||||
char in_string=0;
|
||||
ulong line_number=0;
|
||||
bool ml_comment= 0;
|
||||
@@ -1838,7 +1863,7 @@ static int read_and_execute(bool interactive)
|
||||
bool truncated= 0;
|
||||
status.exit_status=1;
|
||||
|
||||
for (;;)
|
||||
while (!aborted)
|
||||
{
|
||||
if (!interactive)
|
||||
{
|
||||
@@ -1996,11 +2021,11 @@ static COMMANDS *find_command(char *name,char cmd_char)
|
||||
for (uint i= 0; commands[i].name; i++)
|
||||
{
|
||||
if (commands[i].func &&
|
||||
((name &&
|
||||
(((name &&
|
||||
!my_strnncoll(&my_charset_latin1, (uchar*) name, len,
|
||||
(uchar*) commands[i].name, len) &&
|
||||
!commands[i].name[len] &&
|
||||
(!end || (end && commands[i].takes_params))) ||
|
||||
(!end || (end && commands[i].takes_params)))) ||
|
||||
(!name && commands[i].cmd_char == cmd_char)))
|
||||
{
|
||||
DBUG_PRINT("exit",("found command: %s", commands[i].name));
|
||||
@@ -2159,16 +2184,21 @@ static bool add_line(String &buffer,char *line,char *in_string,
|
||||
}
|
||||
buffer.length(0);
|
||||
}
|
||||
else if (!*ml_comment && (!*in_string && (inchar == '#' ||
|
||||
else if (!*ml_comment &&
|
||||
(!*in_string &&
|
||||
(inchar == '#' ||
|
||||
(inchar == '-' && pos[1] == '-' &&
|
||||
/*
|
||||
The third byte is either whitespace or is the
|
||||
end of the line -- which would occur only
|
||||
because of the user sending newline -- which is
|
||||
itself whitespace and should also match.
|
||||
The third byte is either whitespace or is the end of
|
||||
the line -- which would occur only because of the
|
||||
user sending newline -- which is itself whitespace
|
||||
and should also match.
|
||||
We also ignore lines starting with '--', even if there
|
||||
isn't a whitespace after. (This makes it easier to run
|
||||
mysql-test-run cases through the client)
|
||||
*/
|
||||
(my_isspace(charset_info,pos[2]) ||
|
||||
!pos[2])))))
|
||||
((my_isspace(charset_info,pos[2]) || !pos[2]) ||
|
||||
(buffer.is_empty() && out == line))))))
|
||||
{
|
||||
// Flush previously accepted characters
|
||||
if (out != line)
|
||||
@@ -2855,13 +2885,8 @@ com_help(String *buffer __attribute__((unused)),
|
||||
return com_server_help(buffer,line,help_arg);
|
||||
}
|
||||
|
||||
put_info("\nFor information about MySQL products and services, visit:\n"
|
||||
" http://www.mysql.com/\n"
|
||||
"For developer information, including the MySQL Reference Manual, "
|
||||
"visit:\n"
|
||||
" http://dev.mysql.com/\n"
|
||||
"To buy MySQL Enterprise support, training, or other products, visit:\n"
|
||||
" https://shop.mysql.com/\n", INFO_INFO);
|
||||
put_info("\nGeneral information about MariaDB can be found at\n"
|
||||
"http://askmonty.org/wiki/index.php/Manual:Contents\n", INFO_INFO);
|
||||
put_info("List of all MySQL commands:", INFO_INFO);
|
||||
if (!named_cmds)
|
||||
put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO);
|
||||
@@ -3858,8 +3883,9 @@ static int
|
||||
com_edit(String *buffer,char *line __attribute__((unused)))
|
||||
{
|
||||
char filename[FN_REFLEN],buff[160];
|
||||
int fd,tmp;
|
||||
int fd,tmp,error;
|
||||
const char *editor;
|
||||
MY_STAT stat_arg;
|
||||
|
||||
if ((fd=create_temp_file(filename,NullS,"sql", O_CREAT | O_WRONLY,
|
||||
MYF(MY_WME))) < 0)
|
||||
@@ -3875,10 +3901,14 @@ com_edit(String *buffer,char *line __attribute__((unused)))
|
||||
!(editor = (char *)getenv("VISUAL")))
|
||||
editor = "vi";
|
||||
strxmov(buff,editor," ",filename,NullS);
|
||||
if(system(buff) == -1)
|
||||
if ((error= system(buff)))
|
||||
{
|
||||
char errmsg[100];
|
||||
sprintf(errmsg, "Command '%.40s' failed", buff);
|
||||
put_info(errmsg, INFO_ERROR, 0, NullS);
|
||||
goto err;
|
||||
}
|
||||
|
||||
MY_STAT stat_arg;
|
||||
if (!my_stat(filename,&stat_arg,MYF(MY_WME)))
|
||||
goto err;
|
||||
if ((fd = my_open(filename,O_RDONLY, MYF(MY_WME))) < 0)
|
||||
@@ -3961,7 +3991,7 @@ static int
|
||||
com_connect(String *buffer, char *line)
|
||||
{
|
||||
char *tmp, buff[256];
|
||||
bool save_rehash= opt_rehash;
|
||||
my_bool save_rehash= opt_rehash;
|
||||
int error;
|
||||
|
||||
bzero(buff, sizeof(buff));
|
||||
@@ -4018,6 +4048,7 @@ static int com_source(String *buffer, char *line)
|
||||
int error;
|
||||
STATUS old_status;
|
||||
FILE *sql_file;
|
||||
my_bool save_ignore_errors;
|
||||
|
||||
/* Skip space from file name */
|
||||
while (my_isspace(charset_info,*line))
|
||||
@@ -4049,16 +4080,27 @@ static int com_source(String *buffer, char *line)
|
||||
|
||||
/* Save old status */
|
||||
old_status=status;
|
||||
save_ignore_errors= ignore_errors;
|
||||
bfill((char*) &status,sizeof(status),(char) 0);
|
||||
|
||||
status.batch=old_status.batch; // Run in batch mode
|
||||
status.line_buff=line_buff;
|
||||
status.file_name=source_name;
|
||||
glob_buffer.length(0); // Empty command buffer
|
||||
ignore_errors= !batch_abort_on_error;
|
||||
in_com_source= 1;
|
||||
error= read_and_execute(false);
|
||||
ignore_errors= save_ignore_errors;
|
||||
status=old_status; // Continue as before
|
||||
in_com_source= aborted= 0;
|
||||
my_fclose(sql_file,MYF(0));
|
||||
batch_readline_end(line_buff);
|
||||
/*
|
||||
If we got an error during source operation, don't abort the client
|
||||
if ignore_errors is set
|
||||
*/
|
||||
if (error && ignore_errors)
|
||||
error= -1; // Ignore error
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -4247,6 +4289,57 @@ char *get_arg(char *line, my_bool get_next_arg)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
An example of mysql_authentication_dialog_ask callback.
|
||||
|
||||
The C function with the name "mysql_authentication_dialog_ask", if exists,
|
||||
will be used by the "dialog" client authentication plugin when user
|
||||
input is needed. This function should be of mysql_authentication_dialog_ask_t
|
||||
type. If the function does not exists, a built-in implementation will be
|
||||
used.
|
||||
|
||||
@param mysql mysql
|
||||
@param type type of the input
|
||||
1 - normal string input
|
||||
2 - password string
|
||||
@param prompt prompt
|
||||
@param buf a buffer to store the use input
|
||||
@param buf_len the length of the buffer
|
||||
|
||||
@retval a pointer to the user input string.
|
||||
It may be equal to 'buf' or to 'mysql->password'.
|
||||
In all other cases it is assumed to be an allocated
|
||||
string, and the "dialog" plugin will free() it.
|
||||
*/
|
||||
|
||||
extern "C" char *mysql_authentication_dialog_ask(MYSQL *mysql, int type,
|
||||
const char *prompt,
|
||||
char *buf, int buf_len)
|
||||
{
|
||||
char *s=buf;
|
||||
|
||||
fputs("[mariadb] ", stdout);
|
||||
fputs(prompt, stdout);
|
||||
fputs(" ", stdout);
|
||||
|
||||
if (type == 2) /* password */
|
||||
{
|
||||
s= get_tty_password("");
|
||||
strnmov(buf, s, buf_len);
|
||||
buf[buf_len-1]= 0;
|
||||
my_free(s, MYF(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fgets(buf, buf_len-1, stdin))
|
||||
buf[0]= 0;
|
||||
else if (buf[0] && (s= strend(buf))[-1] == '\n')
|
||||
s[-1]= 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
sql_real_connect(char *host,char *database,char *user,char *password,
|
||||
uint silent)
|
||||
@@ -4295,6 +4388,12 @@ sql_real_connect(char *host,char *database,char *user,char *password,
|
||||
|
||||
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
|
||||
|
||||
if (opt_plugin_dir && *opt_plugin_dir)
|
||||
mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
|
||||
|
||||
if (opt_default_auth && *opt_default_auth)
|
||||
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
|
||||
|
||||
if (!mysql_real_connect(&mysql, host, user, password,
|
||||
database, opt_mysql_port, opt_mysql_unix_port,
|
||||
connect_flag | CLIENT_MULTI_STATEMENTS))
|
||||
@@ -4411,6 +4510,7 @@ com_status(String *buffer __attribute__((unused)),
|
||||
tee_fprintf(stdout, "Using outfile:\t\t'%s'\n", opt_outfile ? outfile : "");
|
||||
#endif
|
||||
tee_fprintf(stdout, "Using delimiter:\t%s\n", delimiter);
|
||||
tee_fprintf(stdout, "Server:\t\t\t%s\n", mysql_get_server_name(&mysql));
|
||||
tee_fprintf(stdout, "Server version:\t\t%s\n", server_version_string(&mysql));
|
||||
tee_fprintf(stdout, "Protocol version:\t%d\n", mysql_get_proto_info(&mysql));
|
||||
tee_fprintf(stdout, "Connection:\t\t%s\n", mysql_get_host_info(&mysql));
|
||||
@@ -4579,12 +4679,19 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
|
||||
if (error)
|
||||
{
|
||||
if (sqlstate)
|
||||
(void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate);
|
||||
(void) tee_fprintf(file, "ERROR %d (%s)", error, sqlstate);
|
||||
else
|
||||
(void) tee_fprintf(file, "ERROR %d: ", error);
|
||||
(void) tee_fprintf(file, "ERROR %d", error);
|
||||
}
|
||||
else
|
||||
tee_puts("ERROR: ", file);
|
||||
tee_fputs("ERROR", file);
|
||||
if (status.query_start_line && line_numbers)
|
||||
{
|
||||
(void) fprintf(file," at line %lu",status.query_start_line);
|
||||
if (status.file_name)
|
||||
(void) fprintf(file," in file: '%s'", status.file_name);
|
||||
}
|
||||
tee_fputs(": ", file);
|
||||
}
|
||||
else
|
||||
vidattr(A_BOLD);
|
||||
@@ -4593,7 +4700,7 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
|
||||
}
|
||||
if (unbuffered)
|
||||
fflush(file);
|
||||
return info_type == INFO_ERROR ? -1 : 0;
|
||||
return info_type == INFO_ERROR ? (ignore_errors ? -1 : 1): 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -4759,6 +4866,12 @@ static const char* construct_prompt()
|
||||
case 'd':
|
||||
processed_prompt.append(current_db ? current_db : "(none)");
|
||||
break;
|
||||
case 'N':
|
||||
if (connected)
|
||||
processed_prompt.append(mysql_get_server_name(&mysql));
|
||||
else
|
||||
processed_prompt.append("unknown");
|
||||
break;
|
||||
case 'h':
|
||||
{
|
||||
const char *prompt;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
Copyright (C) 2010 Monty Program Ab
|
||||
|
||||
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
|
||||
@@ -17,7 +18,7 @@
|
||||
#include <sslopt-vars.h>
|
||||
#include "../scripts/mysql_fix_privilege_tables_sql.c"
|
||||
|
||||
#define VER "1.1"
|
||||
#define VER "1.2"
|
||||
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
@@ -34,9 +35,10 @@
|
||||
static char mysql_path[FN_REFLEN];
|
||||
static char mysqlcheck_path[FN_REFLEN];
|
||||
|
||||
static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag,
|
||||
static my_bool opt_force, debug_info_flag, debug_check_flag,
|
||||
opt_systables_only;
|
||||
static uint my_end_arg= 0;
|
||||
static my_bool opt_not_used; /* For compatiblity */
|
||||
static uint my_end_arg= 0, opt_verbose;
|
||||
static char *opt_user= (char*)"root";
|
||||
|
||||
static DYNAMIC_STRING ds_args;
|
||||
@@ -61,12 +63,14 @@ static struct my_option my_long_options[]=
|
||||
{
|
||||
{"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
|
||||
NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"basedir", 'b', "Not used by mysql_upgrade. Only for backward compatibility.",
|
||||
{"basedir", 'b',
|
||||
"Not used by mysql_upgrade. Only for backward compatibility.",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"character-sets-dir", OPT_CHARSETS_DIR,
|
||||
"Directory for character set files.", 0,
|
||||
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
|
||||
"Not used by mysql_upgrade. Only for backward compatibility.",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
{"compress", OPT_COMPRESS,
|
||||
"Not used by mysql_upgrade. Only for backward compatibility.",
|
||||
¬_used, ¬_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"datadir", 'd',
|
||||
"Not used by mysql_upgrade. Only for backward compatibility.",
|
||||
@@ -79,17 +83,16 @@ static struct my_option my_long_options[]=
|
||||
&default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
|
||||
&debug_check_flag, &debug_check_flag, 0,
|
||||
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
&debug_check_flag, &debug_check_flag,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"debug-info", 'T', "Print some debug info at exit.", &debug_info_flag,
|
||||
&debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"default-character-set", OPT_DEFAULT_CHARSET,
|
||||
"Set the default character set.", 0,
|
||||
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
"Not used by mysql_upgrade. Only for backward compatibility.",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade "
|
||||
"has already been executed for the current version of MySQL.",
|
||||
&opt_force, &opt_force, 0,
|
||||
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
&opt_force, &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"host", 'h', "Connect to host.", 0,
|
||||
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"password", 'p',
|
||||
@@ -115,6 +118,8 @@ static struct my_option my_long_options[]=
|
||||
"Base name of shared memory.", 0,
|
||||
0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"silent", 's', "Print less information", &opt_silent,
|
||||
&opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"socket", 'S', "The socket file to use for connection.",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#include <sslopt-longopts.h>
|
||||
@@ -127,8 +132,7 @@ static struct my_option my_long_options[]=
|
||||
{"user", 'u', "User for login if not current user.", &opt_user,
|
||||
&opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"verbose", 'v', "Display more output about the process.",
|
||||
&opt_verbose, &opt_verbose, 0,
|
||||
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
|
||||
&opt_not_used, &opt_not_used, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
|
||||
{"write-binlog", OPT_WRITE_BINLOG,
|
||||
"All commands including mysqlcheck are binlogged. Enabled by default;"
|
||||
"use --skip-write-binlog when commands should not be sent to replication slaves.",
|
||||
@@ -174,7 +178,7 @@ static void verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_verbose)
|
||||
if (opt_silent)
|
||||
return;
|
||||
|
||||
/* Print the verbose message */
|
||||
@@ -270,6 +274,18 @@ get_one_option(int optid, const struct my_option *opt,
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 'v': /* --verbose */
|
||||
opt_verbose++;
|
||||
if (argument == disabled_my_option)
|
||||
{
|
||||
opt_verbose= 0;
|
||||
opt_silent= 1;
|
||||
}
|
||||
add_option= 0;
|
||||
break;
|
||||
case 's':
|
||||
opt_verbose= 0;
|
||||
add_option= 0;
|
||||
break;
|
||||
case 'f': /* --force */
|
||||
add_option= FALSE;
|
||||
break;
|
||||
@@ -430,6 +446,7 @@ static void find_tool(char *tool_executable_name, const char *tool_name,
|
||||
len, self_name, FN_LIBCHAR, tool_name);
|
||||
}
|
||||
|
||||
if (opt_verbose)
|
||||
verbose("Looking for '%s' as: %s", tool_name, tool_executable_name);
|
||||
|
||||
/*
|
||||
@@ -500,7 +517,7 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res,
|
||||
"--database=mysql",
|
||||
"--batch", /* Turns off pager etc. */
|
||||
force ? "--force": "--skip-force",
|
||||
ds_res ? "--silent": "",
|
||||
ds_res || opt_silent ? "--silent": "",
|
||||
"<",
|
||||
query_file_path,
|
||||
"2>&1",
|
||||
@@ -582,7 +599,6 @@ static int upgrade_already_done(void)
|
||||
FILE *in;
|
||||
char upgrade_info_file[FN_REFLEN]= {0};
|
||||
char buf[sizeof(MYSQL_SERVER_VERSION)+1];
|
||||
char *res;
|
||||
|
||||
if (get_upgrade_info_file_name(upgrade_info_file))
|
||||
return 0; /* Could not get filename => not sure */
|
||||
@@ -590,19 +606,15 @@ static int upgrade_already_done(void)
|
||||
if (!(in= my_fopen(upgrade_info_file, O_RDONLY, MYF(0))))
|
||||
return 0; /* Could not open file => not sure */
|
||||
|
||||
/*
|
||||
Read from file, don't care if it fails since it
|
||||
will be detected by the strncmp
|
||||
*/
|
||||
bzero(buf, sizeof(buf));
|
||||
res= fgets(buf, sizeof(buf), in);
|
||||
if (!fgets(buf, sizeof(buf), in))
|
||||
{
|
||||
/* Ignore, will be detected by strncmp() below */
|
||||
}
|
||||
|
||||
my_fclose(in, MYF(0));
|
||||
|
||||
if (!res)
|
||||
return 0; /* Could not read from file => not sure */
|
||||
|
||||
return (strncmp(res, MYSQL_SERVER_VERSION,
|
||||
return (strncmp(buf, MYSQL_SERVER_VERSION,
|
||||
sizeof(MYSQL_SERVER_VERSION)-1)==0);
|
||||
}
|
||||
|
||||
@@ -658,6 +670,8 @@ static void create_mysql_upgrade_info_file(void)
|
||||
|
||||
static void print_conn_args(const char *tool_name)
|
||||
{
|
||||
if (opt_verbose < 2)
|
||||
return;
|
||||
if (conn_args.str[0])
|
||||
verbose("Running '%s' with connection arguments: %s", tool_name,
|
||||
conn_args.str);
|
||||
@@ -673,6 +687,7 @@ static void print_conn_args(const char *tool_name)
|
||||
|
||||
static int run_mysqlcheck_upgrade(void)
|
||||
{
|
||||
verbose("Phase 2/3: Checking and upgrading tables");
|
||||
print_conn_args("mysqlcheck");
|
||||
return run_tool(mysqlcheck_path,
|
||||
NULL, /* Send output from mysqlcheck directly to screen */
|
||||
@@ -681,6 +696,8 @@ static int run_mysqlcheck_upgrade(void)
|
||||
"--check-upgrade",
|
||||
"--all-databases",
|
||||
"--auto-repair",
|
||||
!opt_silent || opt_verbose ? "--verbose": "",
|
||||
opt_silent ? "--silent": "",
|
||||
opt_write_binlog ? "--write-binlog" : "--skip-write-binlog",
|
||||
NULL);
|
||||
}
|
||||
@@ -688,6 +705,7 @@ static int run_mysqlcheck_upgrade(void)
|
||||
|
||||
static int run_mysqlcheck_fixnames(void)
|
||||
{
|
||||
verbose("Phase 1/3: Fixing table and database names");
|
||||
print_conn_args("mysqlcheck");
|
||||
return run_tool(mysqlcheck_path,
|
||||
NULL, /* Send output from mysqlcheck directly to screen */
|
||||
@@ -696,6 +714,8 @@ static int run_mysqlcheck_fixnames(void)
|
||||
"--all-databases",
|
||||
"--fix-db-names",
|
||||
"--fix-table-names",
|
||||
opt_verbose ? "--verbose": "",
|
||||
opt_silent ? "--silent": "",
|
||||
opt_write_binlog ? "--write-binlog" : "--skip-write-binlog",
|
||||
NULL);
|
||||
}
|
||||
@@ -765,7 +785,7 @@ static int run_sql_fix_privilege_tables(void)
|
||||
if (init_dynamic_string(&ds_result, "", 512, 512))
|
||||
die("Out of memory");
|
||||
|
||||
verbose("Running 'mysql_fix_privilege_tables'...");
|
||||
verbose("Phase 3/3: Running 'mysql_fix_privilege_tables'...");
|
||||
run_query(mysql_fix_privilege_tables,
|
||||
&ds_result, /* Collect result */
|
||||
TRUE);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <mysql.h>
|
||||
#include <sql_common.h>
|
||||
|
||||
#define ADMIN_VERSION "8.42"
|
||||
#define ADMIN_VERSION "9.0"
|
||||
#define MAX_MYSQL_VAR 512
|
||||
#define SHUTDOWN_DEF_TIMEOUT 3600 /* Wait for shutdown */
|
||||
#define MAX_TRUNC_LENGTH 3
|
||||
@@ -97,7 +97,10 @@ enum commands {
|
||||
ADMIN_FLUSH_HOSTS, ADMIN_FLUSH_TABLES, ADMIN_PASSWORD,
|
||||
ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
|
||||
ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE,
|
||||
ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD
|
||||
ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD, ADMIN_FLUSH_SLOW_LOG,
|
||||
ADMIN_FLUSH_TABLE_STATISTICS, ADMIN_FLUSH_INDEX_STATISTICS,
|
||||
ADMIN_FLUSH_USER_STATISTICS, ADMIN_FLUSH_CLIENT_STATISTICS,
|
||||
ADMIN_FLUSH_ALL_STATUS, ADMIN_FLUSH_ALL_STATISTICS
|
||||
};
|
||||
static const char *command_names[]= {
|
||||
"create", "drop", "shutdown",
|
||||
@@ -107,7 +110,10 @@ static const char *command_names[]= {
|
||||
"flush-hosts", "flush-tables", "password",
|
||||
"ping", "extended-status", "flush-status",
|
||||
"flush-privileges", "start-slave", "stop-slave",
|
||||
"flush-threads","old-password",
|
||||
"flush-threads", "old-password", "flush-slow-log",
|
||||
"flush-table-statistics", "flush-index-statistics",
|
||||
"flush-user-statistics", "flush-client-statistics",
|
||||
"flush-all-status", "flush-all-statistics",
|
||||
NullS
|
||||
};
|
||||
|
||||
@@ -572,11 +578,12 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
If this behaviour is ever changed, Docs should be notified.
|
||||
*/
|
||||
|
||||
struct rand_struct rand_st;
|
||||
struct my_rnd_struct rand_st;
|
||||
|
||||
for (; argc > 0 ; argv++,argc--)
|
||||
{
|
||||
switch (find_type(argv[0],&command_typelib,2)) {
|
||||
int command;
|
||||
switch ((command= find_type(argv[0],&command_typelib,2))) {
|
||||
case ADMIN_CREATE:
|
||||
{
|
||||
char buff[FN_REFLEN+20];
|
||||
@@ -653,7 +660,11 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
if (mysql_refresh(mysql,
|
||||
(uint) ~(REFRESH_GRANT | REFRESH_STATUS |
|
||||
REFRESH_READ_LOCK | REFRESH_SLAVE |
|
||||
REFRESH_MASTER)))
|
||||
REFRESH_MASTER | REFRESH_TABLE_STATS |
|
||||
REFRESH_INDEX_STATS |
|
||||
REFRESH_USER_STATS |
|
||||
REFRESH_SLOW_QUERY_LOG |
|
||||
REFRESH_CLIENT_STATS)))
|
||||
{
|
||||
my_printf_error(0, "refresh failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
@@ -671,7 +682,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
case ADMIN_VER:
|
||||
new_line=1;
|
||||
print_version();
|
||||
puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
|
||||
puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc,\n"
|
||||
"2009 Monty Program Ab");
|
||||
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
|
||||
printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
|
||||
printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
|
||||
@@ -847,9 +859,19 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
}
|
||||
case ADMIN_FLUSH_LOGS:
|
||||
{
|
||||
if (mysql_refresh(mysql,REFRESH_LOG))
|
||||
if (mysql_query(mysql,"flush logs"))
|
||||
{
|
||||
my_printf_error(0, "refresh failed; error: '%s'", error_flags,
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_SLOW_LOG:
|
||||
{
|
||||
if (mysql_query(mysql,"flush slow query logs"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
@@ -859,7 +881,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
{
|
||||
if (mysql_query(mysql,"flush hosts"))
|
||||
{
|
||||
my_printf_error(0, "refresh failed; error: '%s'", error_flags,
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
@@ -869,7 +891,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
{
|
||||
if (mysql_query(mysql,"flush tables"))
|
||||
{
|
||||
my_printf_error(0, "refresh failed; error: '%s'", error_flags,
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
@@ -879,7 +901,71 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
{
|
||||
if (mysql_query(mysql,"flush status"))
|
||||
{
|
||||
my_printf_error(0, "refresh failed; error: '%s'", error_flags,
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_TABLE_STATISTICS:
|
||||
{
|
||||
if (mysql_query(mysql,"flush table_statistics"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_INDEX_STATISTICS:
|
||||
{
|
||||
if (mysql_query(mysql,"flush index_statistics"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_USER_STATISTICS:
|
||||
{
|
||||
if (mysql_query(mysql,"flush user_statistics"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_CLIENT_STATISTICS:
|
||||
{
|
||||
if (mysql_query(mysql,"flush client_statistics"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_ALL_STATISTICS:
|
||||
{
|
||||
if (mysql_query(mysql,
|
||||
"flush table_statistics,index_statistics,"
|
||||
"user_statistics,client_statistics"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADMIN_FLUSH_ALL_STATUS:
|
||||
{
|
||||
if (mysql_query(mysql,
|
||||
"flush status,table_statistics,index_statistics,"
|
||||
"user_statistics,client_statistics"))
|
||||
{
|
||||
my_printf_error(0, "flush failed; error: '%s'", error_flags,
|
||||
mysql_error(mysql));
|
||||
return -1;
|
||||
}
|
||||
@@ -893,7 +979,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
char *typed_password= NULL, *verified= NULL;
|
||||
/* Do initialization the same way as we do in mysqld */
|
||||
start_time=time((time_t*) 0);
|
||||
randominit(&rand_st,(ulong) start_time,(ulong) start_time/2);
|
||||
my_rnd_init(&rand_st,(ulong) start_time,(ulong) start_time/2);
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
@@ -1070,7 +1156,8 @@ static void print_version(void)
|
||||
static void usage(void)
|
||||
{
|
||||
print_version();
|
||||
puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
|
||||
puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc,\n"
|
||||
"2009 Monty Program Ab");
|
||||
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
|
||||
puts("Administration program for the mysqld daemon.");
|
||||
printf("Usage: %s [OPTIONS] command command....\n", my_progname);
|
||||
@@ -1082,12 +1169,19 @@ static void usage(void)
|
||||
debug Instruct server to write debug information to log\n\
|
||||
drop databasename Delete a database and all its tables\n\
|
||||
extended-status Gives an extended status message from the server\n\
|
||||
flush-all-statistics Flush all statistics tables\n\
|
||||
flush-all-status Flush status and statistics\n\
|
||||
flush-client-statistics Flush client statistics\n\
|
||||
flush-hosts Flush all cached hosts\n\
|
||||
flush-index-statistics Flush index statistics\n\
|
||||
flush-logs Flush all logs\n\
|
||||
flush-privileges Reload grant tables (same as reload)\n\
|
||||
flush-slow-log Flush slow query log\n\
|
||||
flush-status Clear status variables\n\
|
||||
flush-table-statistics Clear table statistics\n\
|
||||
flush-tables Flush all tables\n\
|
||||
flush-threads Flush the thread cache\n\
|
||||
flush-privileges Reload grant tables (same as reload)\n\
|
||||
flush-user-statistics Flush user statistics\n\
|
||||
kill id,id,... Kill mysql threads");
|
||||
#if MYSQL_VERSION_ID >= 32200
|
||||
puts("\
|
||||
@@ -1377,7 +1471,7 @@ static my_bool wait_pidfile(char *pidfile, time_t last_modified,
|
||||
struct stat *pidfile_status)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
int error= 1;
|
||||
my_bool error= 1;
|
||||
uint count= 0;
|
||||
DBUG_ENTER("wait_pidfile");
|
||||
|
||||
|
||||
@@ -35,6 +35,15 @@
|
||||
#include "log_event.h"
|
||||
#include "sql_common.h"
|
||||
|
||||
/* Needed for Rpl_filter */
|
||||
CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci;
|
||||
|
||||
#include "sql_string.h" // needed for Rpl_filter
|
||||
#include "sql_list.h" // needed for Rpl_filter
|
||||
#include "rpl_filter.h"
|
||||
|
||||
Rpl_filter *binlog_filter;
|
||||
|
||||
#define BIN_LOG_HEADER_SIZE 4
|
||||
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
|
||||
|
||||
@@ -436,7 +445,7 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
|
||||
ptr= fname + target_dir_name_len;
|
||||
memcpy(ptr,bname,blen);
|
||||
ptr+= blen;
|
||||
ptr+= sprintf(ptr, "-%x", file_id);
|
||||
ptr+= my_sprintf(ptr, (ptr, "-%x", file_id));
|
||||
|
||||
if ((file= create_unique_file(fname,ptr)) < 0)
|
||||
{
|
||||
@@ -625,6 +634,42 @@ static bool shall_skip_database(const char *log_dbname)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Print "use <db>" statement when current db is to be changed.
|
||||
|
||||
We have to control emiting USE statements according to rewrite-db options.
|
||||
We have to do it here (see process_event() below) and to suppress
|
||||
producing USE statements by corresponding log event print-functions.
|
||||
*/
|
||||
|
||||
void print_use_stmt(PRINT_EVENT_INFO* pinfo, const char* db, size_t db_len)
|
||||
{
|
||||
// pinfo->db is the current db.
|
||||
// If current db is the same as required db, do nothing.
|
||||
if (!db || !memcmp(pinfo->db, db, db_len + 1))
|
||||
return;
|
||||
|
||||
// Current db and required db are different.
|
||||
// Check for rewrite rule for required db. (Note that in a rewrite rule
|
||||
// neither db_from nor db_to part can be empty).
|
||||
size_t len_to= 0;
|
||||
const char *db_to= binlog_filter->get_rewrite_db(db, &len_to);
|
||||
|
||||
// If there is no rewrite rule for db (in this case len_to is left = 0),
|
||||
// printing of the corresponding USE statement is left for log event
|
||||
// print-function.
|
||||
if (!len_to)
|
||||
return;
|
||||
|
||||
// In case of rewrite rule print USE statement for db_to
|
||||
fprintf(result_file, "use %s%s\n", db_to, pinfo->delimiter);
|
||||
|
||||
// Copy the *original* db to pinfo to suppress emiting
|
||||
// of USE stmts by log_event print-functions.
|
||||
memcpy(pinfo->db, db, db_len + 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prints the given event in base64 format.
|
||||
|
||||
@@ -736,9 +781,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
|
||||
switch (ev_type) {
|
||||
case QUERY_EVENT:
|
||||
if (!((Query_log_event*)ev)->is_trans_keyword() &&
|
||||
shall_skip_database(((Query_log_event*)ev)->db))
|
||||
{
|
||||
Query_log_event *qe= (Query_log_event*)ev;
|
||||
if (!qe->is_trans_keyword() && shall_skip_database(qe->db))
|
||||
goto end;
|
||||
print_use_stmt(print_event_info, qe->db, qe->db_len);
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS)
|
||||
{
|
||||
if ((retval= write_event_header_and_base64(ev, result_file,
|
||||
@@ -749,6 +796,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
else
|
||||
ev->print(result_file, print_event_info);
|
||||
break;
|
||||
}
|
||||
|
||||
case CREATE_FILE_EVENT:
|
||||
{
|
||||
@@ -876,6 +924,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
|
||||
if (!shall_skip_database(exlq->db))
|
||||
{
|
||||
print_use_stmt(print_event_info, exlq->db, exlq->db_len);
|
||||
if (fname)
|
||||
{
|
||||
convert_path_to_forward_slashes(fname);
|
||||
@@ -899,6 +948,13 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
destroy_evt= FALSE;
|
||||
goto end;
|
||||
}
|
||||
size_t len_to= 0;
|
||||
const char* db_to= binlog_filter->get_rewrite_db(map->get_db_name(), &len_to);
|
||||
if (len_to && map->rewrite_db(db_to, len_to, glob_description_event))
|
||||
{
|
||||
error("Could not rewrite database name");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
case WRITE_ROWS_EVENT:
|
||||
case DELETE_ROWS_EVENT:
|
||||
@@ -983,14 +1039,16 @@ err:
|
||||
retval= ERROR_STOP;
|
||||
end:
|
||||
rec_count++;
|
||||
|
||||
/*
|
||||
Destroy the log_event object. If reading from a remote host,
|
||||
Destroy the log_event object.
|
||||
MariaDB MWL#36: mainline does this:
|
||||
If reading from a remote host,
|
||||
set the temp_buf to NULL so that memory isn't freed twice.
|
||||
We no longer do that, we use Rpl_filter::event_owns_temp_buf instead.
|
||||
*/
|
||||
if (ev)
|
||||
{
|
||||
if (remote_opt)
|
||||
ev->temp_buf= 0;
|
||||
if (destroy_evt) /* destroy it later if not set (ignored table map) */
|
||||
delete ev;
|
||||
}
|
||||
@@ -1147,6 +1205,10 @@ that may lead to an endless loop.",
|
||||
"Used to reserve file descriptors for use by this program.",
|
||||
&open_files_limit, &open_files_limit, 0, GET_ULONG,
|
||||
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
|
||||
{"rewrite-db", OPT_REWRITE_DB,
|
||||
"Updates to a database with a different name than the original. \
|
||||
Example: rewrite-db='from->to'.",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -1330,6 +1392,53 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
(find_type_or_exit(argument, &base64_output_mode_typelib, opt->name)-1);
|
||||
}
|
||||
break;
|
||||
case OPT_REWRITE_DB: // db_from->db_to
|
||||
{
|
||||
/* See also handling of OPT_REPLICATE_REWRITE_DB in sql/mysqld.cc */
|
||||
char* ptr;
|
||||
char* key= argument; // db-from
|
||||
char* val; // db-to
|
||||
|
||||
// Where key begins
|
||||
while (*key && my_isspace(&my_charset_latin1, *key))
|
||||
key++;
|
||||
|
||||
// Where val begins
|
||||
if (!(ptr= strstr(argument, "->")))
|
||||
{
|
||||
sql_print_error("Bad syntax in rewrite-db: missing '->'!\n");
|
||||
return 1;
|
||||
}
|
||||
val= ptr + 2;
|
||||
while (*val && my_isspace(&my_charset_latin1, *val))
|
||||
val++;
|
||||
|
||||
// Write \0 and skip blanks at the end of key
|
||||
*ptr-- = 0;
|
||||
while (my_isspace(&my_charset_latin1, *ptr) && ptr > argument)
|
||||
*ptr-- = 0;
|
||||
|
||||
if (!*key)
|
||||
{
|
||||
sql_print_error("Bad syntax in rewrite-db: empty db-from!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Skip blanks at the end of val
|
||||
ptr= val;
|
||||
while (*ptr && !my_isspace(&my_charset_latin1, *ptr))
|
||||
ptr++;
|
||||
*ptr= 0;
|
||||
|
||||
if (!*val)
|
||||
{
|
||||
sql_print_error("Bad syntax in rewrite-db: empty db-to!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
binlog_filter->add_db_rewrite(key, val);
|
||||
break;
|
||||
}
|
||||
case 'v':
|
||||
if (argument == disabled_my_option)
|
||||
verbose= 0;
|
||||
@@ -1374,6 +1483,10 @@ static int parse_args(int *argc, char*** argv)
|
||||
*/
|
||||
static Exit_status safe_connect()
|
||||
{
|
||||
/* Close and old connections to MySQL */
|
||||
if (mysql)
|
||||
mysql_close(mysql);
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
if (!mysql)
|
||||
@@ -1599,7 +1712,7 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
|
||||
If reading from a remote host, ensure the temp_buf for the
|
||||
Log_event class is pointing to the incoming stream.
|
||||
*/
|
||||
ev->register_temp_buf((char *) net->read_pos + 1);
|
||||
ev->register_temp_buf((char *) net->read_pos + 1, FALSE);
|
||||
|
||||
Log_event_type type= ev->get_type_code();
|
||||
if (glob_description_event->binlog_version >= 3 ||
|
||||
@@ -1999,6 +2112,8 @@ end:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Used in sql_alloc(). Inited and freed in main() */
|
||||
MEM_ROOT s_mem_root;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
@@ -2011,8 +2126,16 @@ int main(int argc, char** argv)
|
||||
|
||||
my_init_time(); // for time functions
|
||||
|
||||
init_alloc_root(&s_mem_root, 16384, 0);
|
||||
if (!(binlog_filter= new Rpl_filter))
|
||||
{
|
||||
error("Failed to create Rpl_filter");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (load_defaults("my", load_default_groups, &argc, &argv))
|
||||
exit(1);
|
||||
|
||||
defaults_argv= argv;
|
||||
parse_args(&argc, (char***)&argv);
|
||||
|
||||
@@ -2100,6 +2223,8 @@ int main(int argc, char** argv)
|
||||
if (result_file != stdout)
|
||||
my_fclose(result_file, MYF(0));
|
||||
cleanup();
|
||||
delete binlog_filter;
|
||||
free_root(&s_mem_root, MYF(0));
|
||||
free_defaults(defaults_argv);
|
||||
my_free_open_file_info();
|
||||
load_processor.destroy();
|
||||
@@ -2111,6 +2236,12 @@ int main(int argc, char** argv)
|
||||
DBUG_RETURN(retval == ERROR_STOP ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void *sql_alloc(size_t size)
|
||||
{
|
||||
return alloc_root(&s_mem_root, size);
|
||||
}
|
||||
|
||||
/*
|
||||
We must include this here as it's compiled with different options for
|
||||
the server
|
||||
@@ -2122,3 +2253,6 @@ int main(int argc, char** argv)
|
||||
#include "log_event.cc"
|
||||
#include "log_event_old.cc"
|
||||
#include "rpl_utility.cc"
|
||||
#include "sql_string.cc"
|
||||
#include "sql_list.cc"
|
||||
#include "rpl_filter.cc"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* Copyright (C) 2000 MySQL AB, 2009 Sun Microsystems, Inc
|
||||
/* Copyright (C) 2000 MySQL AB & Jani Tolonen
|
||||
Copyright (C) 2009 Sun Microsystems, Inc
|
||||
Copyright (C) 2010 Monty Program Ab
|
||||
|
||||
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
|
||||
@@ -15,7 +17,7 @@
|
||||
|
||||
/* By Jani Tolonen, 2001-04-20, MySQL Development Team */
|
||||
|
||||
#define CHECK_VERSION "2.5.0"
|
||||
#define CHECK_VERSION "2.6.0"
|
||||
|
||||
#include "client_priv.h"
|
||||
#include <m_ctype.h>
|
||||
@@ -67,8 +69,8 @@ static struct my_option my_long_options[] =
|
||||
&opt_auto_repair, &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0,
|
||||
0, 0, 0, 0, 0},
|
||||
{"character-sets-dir", OPT_CHARSETS_DIR,
|
||||
"Directory for character set files.", &charsets_dir,
|
||||
&charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
"Directory for character set files.", (char**) &charsets_dir,
|
||||
(char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
|
||||
0, 0, 0, 0},
|
||||
{"check-only-changed", 'C',
|
||||
@@ -216,24 +218,26 @@ static void usage(void)
|
||||
{
|
||||
print_version();
|
||||
puts("By Jani Tolonen, 2001-04-20, MySQL Development Team.\n");
|
||||
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
|
||||
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
|
||||
puts("and you are welcome to modify and redistribute it under the GPL license.\n");
|
||||
printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
|
||||
printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
|
||||
my_progname);
|
||||
printf("OR %s [OPTIONS] --all-databases\n\n", my_progname);
|
||||
puts("This program can be used to CHECK (-c, -m, -C), REPAIR (-r), ANALYZE (-a),");
|
||||
puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
|
||||
puts("used at the same time. Not all options are supported by all storage engines.");
|
||||
puts("Please consult the MySQL manual for latest information about the");
|
||||
puts("above. The options -c, -r, -a, and -o are exclusive to each other, which");
|
||||
puts("The options -c, -r, -a, and -o are exclusive to each other, which");
|
||||
puts("means that the last option will be used, if several was specified.\n");
|
||||
puts("The option -c will be used by default, if none was specified. You");
|
||||
puts("can change the default behavior by making a symbolic link, or");
|
||||
puts("The option -c (--check) will be used by default, if none was specified.");
|
||||
puts("You can change the default behavior by making a symbolic link, or");
|
||||
puts("copying this file somewhere with another name, the alternatives are:");
|
||||
puts("mysqlrepair: The default option will be -r");
|
||||
puts("mysqlanalyze: The default option will be -a");
|
||||
puts("mysqloptimize: The default option will be -o\n");
|
||||
printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
|
||||
printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n",
|
||||
my_progname);
|
||||
printf("OR %s [OPTIONS] --all-databases\n", my_progname);
|
||||
puts("Please consult the MariaDB/MySQL knowledgebase at");
|
||||
puts("http://kb.askmonty.org/v/mysqlcheck for latest information about");
|
||||
puts("this program.");
|
||||
print_defaults("my", load_default_groups);
|
||||
my_print_help(my_long_options);
|
||||
my_print_variables(my_long_options);
|
||||
@@ -406,6 +410,8 @@ static int process_all_databases()
|
||||
MYF(0), mysql_error(sock));
|
||||
return 1;
|
||||
}
|
||||
if (verbose)
|
||||
printf("Processing databases\n");
|
||||
while ((row = mysql_fetch_row(tableres)))
|
||||
{
|
||||
if (process_one_db(row[0]))
|
||||
@@ -419,6 +425,8 @@ static int process_all_databases()
|
||||
static int process_databases(char **db_names)
|
||||
{
|
||||
int result = 0;
|
||||
if (verbose)
|
||||
printf("Processing databases\n");
|
||||
for ( ; *db_names ; db_names++)
|
||||
{
|
||||
if (process_one_db(*db_names))
|
||||
@@ -511,6 +519,7 @@ static int process_all_tables_in_db(char *database)
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
uint num_columns;
|
||||
my_bool system_database= 0;
|
||||
|
||||
LINT_INIT(res);
|
||||
if (use_db(database))
|
||||
@@ -524,6 +533,9 @@ static int process_all_tables_in_db(char *database)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(database, "mysql") || !strcmp(database, "MYSQL"))
|
||||
system_database= 1;
|
||||
|
||||
num_columns= mysql_num_fields(res);
|
||||
|
||||
if (opt_all_in_1 && what_to_do != DO_UPGRADE)
|
||||
@@ -566,6 +578,10 @@ static int process_all_tables_in_db(char *database)
|
||||
/* Skip views if we don't perform renaming. */
|
||||
if ((what_to_do != DO_UPGRADE) && (num_columns == 2) && (strcmp(row[1], "VIEW") == 0))
|
||||
continue;
|
||||
if (system_database &&
|
||||
(!strcmp(row[0], "general_log") ||
|
||||
!strcmp(row[0], "slow_log")))
|
||||
continue; /* Skip logging tables */
|
||||
|
||||
handle_request_for_tables(row[0], fixed_name_length(row[0]));
|
||||
}
|
||||
@@ -614,6 +630,8 @@ static int fix_database_storage_name(const char *name)
|
||||
|
||||
static int process_one_db(char *database)
|
||||
{
|
||||
if (verbose)
|
||||
puts(database);
|
||||
if (what_to_do == DO_UPGRADE)
|
||||
{
|
||||
int rc= 0;
|
||||
@@ -696,7 +714,8 @@ static int handle_request_for_tables(char *tables, uint length)
|
||||
if (opt_all_in_1)
|
||||
{
|
||||
/* No backticks here as we added them before */
|
||||
query_length= sprintf(query, "%s TABLE %s %s", op, tables, options);
|
||||
query_length= my_sprintf(query,
|
||||
(query, "%s TABLE %s %s", op, tables, options));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -723,7 +742,7 @@ static void print_result()
|
||||
{
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char prev[NAME_LEN*2+2];
|
||||
char prev[(NAME_LEN+9)*2+2];
|
||||
uint i;
|
||||
my_bool found_error=0;
|
||||
|
||||
@@ -753,6 +772,14 @@ static void print_result()
|
||||
printf("%-50s %s", row[0], row[3]);
|
||||
else if (!status && changed)
|
||||
{
|
||||
/*
|
||||
If the error message includes REPAIR TABLE, we assume it means
|
||||
we have to run upgrade on it. In this case we write a nicer message
|
||||
than "Please do "REPAIR TABLE""...
|
||||
*/
|
||||
if (!strcmp(row[2],"error") && strinstr(row[3],"REPAIR TABLE") != 0)
|
||||
printf("%-50s %s", row[0], "Needs upgrade");
|
||||
else
|
||||
printf("%s\n%-9s: %s", row[0], row[2], row[3]);
|
||||
if (strcmp(row[2],"note"))
|
||||
found_error=1;
|
||||
@@ -772,7 +799,7 @@ static void print_result()
|
||||
static int dbConnect(char *host, char *user, char *passwd)
|
||||
{
|
||||
DBUG_ENTER("dbConnect");
|
||||
if (verbose)
|
||||
if (verbose > 1)
|
||||
{
|
||||
fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
|
||||
}
|
||||
@@ -804,7 +831,7 @@ static int dbConnect(char *host, char *user, char *passwd)
|
||||
|
||||
static void dbDisconnect(char *host)
|
||||
{
|
||||
if (verbose)
|
||||
if (verbose > 1)
|
||||
fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
|
||||
mysql_close(sock);
|
||||
} /* dbDisconnect */
|
||||
@@ -848,7 +875,8 @@ int main(int argc, char **argv)
|
||||
|
||||
if (!opt_write_binlog)
|
||||
{
|
||||
if (disable_binlog()) {
|
||||
if (disable_binlog())
|
||||
{
|
||||
first_error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -212,8 +212,8 @@ static struct my_option my_long_options[] =
|
||||
&opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"character-sets-dir", OPT_CHARSETS_DIR,
|
||||
"Directory for character set files.", &charsets_dir,
|
||||
&charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
"Directory for character set files.", (char**) &charsets_dir,
|
||||
(char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"comments", 'i', "Write additional information.",
|
||||
&opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG,
|
||||
1, 0, 0, 0, 0, 0},
|
||||
@@ -250,8 +250,8 @@ static struct my_option my_long_options[] =
|
||||
{"debug", '#', "This is a non-debug version. Catch this and exit.",
|
||||
0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#else
|
||||
{"debug", '#', "Output debug log.", &default_dbug_option,
|
||||
&default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"debug", '#', "Output debug log.", (char**) &default_dbug_option,
|
||||
(char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
|
||||
&debug_check_flag, &debug_check_flag, 0,
|
||||
@@ -974,7 +974,7 @@ static int get_options(int *argc, char ***argv)
|
||||
static void DB_error(MYSQL *mysql_arg, const char *when)
|
||||
{
|
||||
DBUG_ENTER("DB_error");
|
||||
maybe_die(EX_MYSQLERR, "Got error: %d: %s %s",
|
||||
maybe_die(EX_MYSQLERR, "Got error: %d: \"%s\" %s",
|
||||
mysql_errno(mysql_arg), mysql_error(mysql_arg), when);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -1399,6 +1399,7 @@ static void free_resources()
|
||||
if (md_result_file && md_result_file != stdout)
|
||||
my_fclose(md_result_file, MYF(0));
|
||||
my_free(opt_password);
|
||||
my_free(current_host);
|
||||
if (my_hash_inited(&ignore_table))
|
||||
my_hash_free(&ignore_table);
|
||||
if (extended_insert)
|
||||
@@ -4206,7 +4207,7 @@ static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
|
||||
}
|
||||
mysql_free_result(table_res);
|
||||
}
|
||||
DBUG_PRINT("exit", ("new_table_name: %s", name));
|
||||
DBUG_PRINT("exit", ("new_table_name: %s", val_or_null(name)));
|
||||
DBUG_RETURN(name);
|
||||
}
|
||||
|
||||
@@ -4928,6 +4929,7 @@ static my_bool get_view_structure(char *table, char* db)
|
||||
field= mysql_fetch_field_direct(table_res, 0);
|
||||
if (strcmp(field->name, "View") != 0)
|
||||
{
|
||||
mysql_free_result(table_res);
|
||||
switch_character_set_results(mysql, default_charset);
|
||||
verbose_msg("-- It's base table, skipped\n");
|
||||
DBUG_RETURN(0);
|
||||
@@ -4937,8 +4939,10 @@ static my_bool get_view_structure(char *table, char* db)
|
||||
if (path)
|
||||
{
|
||||
if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
|
||||
{
|
||||
mysql_free_result(table_res);
|
||||
DBUG_RETURN(1);
|
||||
|
||||
}
|
||||
write_header(sql_file, db);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ static char *shared_memory_base_name=0;
|
||||
static struct my_option my_long_options[] =
|
||||
{
|
||||
{"character-sets-dir", OPT_CHARSETS_DIR,
|
||||
"Directory for character set files.", &charsets_dir,
|
||||
&charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
"Directory for character set files.", (char**) &charsets_dir,
|
||||
(char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"default-character-set", OPT_DEFAULT_CHARSET,
|
||||
"Set the default character set.", &default_charset,
|
||||
&default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
@@ -161,7 +161,7 @@ int main(int argc, char **argv)
|
||||
static struct my_option my_long_options[] =
|
||||
{
|
||||
{"character-sets-dir", 'c', "Directory for character set files.",
|
||||
&charsets_dir, &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0,
|
||||
(char**) &charsets_dir, (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0,
|
||||
0, 0, 0, 0, 0},
|
||||
{"default-character-set", OPT_DEFAULT_CHARSET,
|
||||
"Set the default character set.", &default_charset,
|
||||
|
||||
@@ -292,6 +292,25 @@ static int gettimeofday(struct timeval *tp, void *tzp)
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_mysql_connect_options(MYSQL *mysql)
|
||||
{
|
||||
if (opt_compress)
|
||||
mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (opt_use_ssl)
|
||||
mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
|
||||
opt_ssl_capath, opt_ssl_cipher);
|
||||
#endif
|
||||
if (opt_protocol)
|
||||
mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
|
||||
#ifdef HAVE_SMEM
|
||||
if (shared_memory_base_name)
|
||||
mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
|
||||
#endif
|
||||
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
MYSQL mysql;
|
||||
@@ -327,20 +346,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
mysql_init(&mysql);
|
||||
if (opt_compress)
|
||||
mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (opt_use_ssl)
|
||||
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
|
||||
opt_ssl_capath, opt_ssl_cipher);
|
||||
#endif
|
||||
if (opt_protocol)
|
||||
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
|
||||
#ifdef HAVE_SMEM
|
||||
if (shared_memory_base_name)
|
||||
mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
|
||||
#endif
|
||||
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
|
||||
set_mysql_connect_options(&mysql);
|
||||
|
||||
if (!opt_only_print)
|
||||
{
|
||||
@@ -450,7 +456,16 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
|
||||
|
||||
/* First we create */
|
||||
if (create_statements)
|
||||
{
|
||||
/*
|
||||
If we have an --engine option, then we indicate
|
||||
create_schema() to add the engine type to the DDL.
|
||||
*/
|
||||
if (eptr)
|
||||
create_statements->type= CREATE_TABLE_TYPE;
|
||||
|
||||
create_schema(mysql, create_schema_string, create_statements, eptr);
|
||||
}
|
||||
|
||||
/*
|
||||
If we generated GUID we need to build a list of them from creation that
|
||||
@@ -464,9 +479,9 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
|
||||
if (commit_rate)
|
||||
run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
|
||||
|
||||
if (pre_system)
|
||||
if ((sysret= system(pre_system)) != 0)
|
||||
fprintf(stderr, "Warning: Execution of pre_system option returned %d.\n",
|
||||
if (pre_system && (sysret= system(pre_system)) != 0)
|
||||
fprintf(stderr,
|
||||
"Warning: Execution of pre_system option returned %d.\n",
|
||||
sysret);
|
||||
|
||||
/*
|
||||
@@ -481,11 +496,10 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
|
||||
if (post_statements)
|
||||
run_statements(mysql, post_statements);
|
||||
|
||||
if (post_system)
|
||||
if ((sysret= system(post_system)) != 0)
|
||||
fprintf(stderr, "Warning: Execution of post_system option returned %d.\n",
|
||||
if (post_system && (sysret= system(post_system)) != 0)
|
||||
fprintf(stderr,
|
||||
"Warning: Execution of post_system option returned %d.\n",
|
||||
sysret);
|
||||
|
||||
/* We are finished with this run */
|
||||
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
|
||||
drop_primary_key_list();
|
||||
@@ -530,7 +544,7 @@ static struct my_option my_long_options[] =
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
|
||||
"Specify test load type: mixed, update, write, key, or read; default is mixed.",
|
||||
&auto_generate_sql_type, &auto_generate_sql_type,
|
||||
(char**) &auto_generate_sql_type, (char**) &auto_generate_sql_type,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"auto-generate-sql-secondary-indexes",
|
||||
OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
|
||||
@@ -561,13 +575,13 @@ static struct my_option my_long_options[] =
|
||||
&opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
|
||||
0, 0, 0},
|
||||
{"concurrency", 'c', "Number of clients to simulate for query to run.",
|
||||
&concurrency_str, &concurrency_str, 0, GET_STR,
|
||||
(char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR,
|
||||
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
|
||||
&create_string, &create_string, 0, GET_STR, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
|
||||
&create_schema_string, &create_schema_string, 0, GET_STR,
|
||||
(char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR,
|
||||
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"csv", OPT_SLAP_CSV,
|
||||
"Generate CSV output to named file or to stdout if no file is named.",
|
||||
@@ -577,7 +591,7 @@ static struct my_option my_long_options[] =
|
||||
0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#else
|
||||
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
|
||||
&default_dbug_option, &default_dbug_option, 0, GET_STR,
|
||||
(char**) &default_dbug_option, (char**) &default_dbug_option, 0, GET_STR,
|
||||
OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
|
||||
@@ -587,13 +601,16 @@ static struct my_option my_long_options[] =
|
||||
&debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"delimiter", 'F',
|
||||
"Delimiter to use in SQL statements supplied in file or command line.",
|
||||
&delimiter, &delimiter, 0, GET_STR, REQUIRED_ARG,
|
||||
(char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"detach", OPT_SLAP_DETACH,
|
||||
"Detach (close and reopen) connections after X number of requests.",
|
||||
&detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"engine", 'e', "Storage engine to use for creating the table.",
|
||||
{"engine", 'e',
|
||||
"Comma separated list of storage engines to use for creating the table."
|
||||
" The test is run for each engine. You can also specify an option for an "
|
||||
"engine after a `:', like memory:max_row=2300",
|
||||
&default_engine, &default_engine, 0,
|
||||
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"host", 'h', "Connect to host.", &host, &host, 0, GET_STR,
|
||||
@@ -602,11 +619,11 @@ static struct my_option my_long_options[] =
|
||||
&iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
|
||||
{"number-char-cols", 'x',
|
||||
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
|
||||
&num_char_cols_opt, &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
|
||||
(char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"number-int-cols", 'y',
|
||||
"Number of INT columns to create in table if specifying --auto-generate-sql.",
|
||||
&num_int_cols_opt, &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
|
||||
(char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
|
||||
"Limit each client to this number of queries (this is not exact).",
|
||||
@@ -958,6 +975,7 @@ build_update_string(void)
|
||||
ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
|
||||
else
|
||||
ptr->type= UPDATE_TYPE;
|
||||
|
||||
strmov(ptr->string, update_string.str);
|
||||
dynstr_free(&update_string);
|
||||
DBUG_RETURN(ptr);
|
||||
@@ -1117,6 +1135,7 @@ build_select_string(my_bool key)
|
||||
ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
|
||||
else
|
||||
ptr->type= SELECT_TYPE;
|
||||
|
||||
strmov(ptr->string, query_string.str);
|
||||
dynstr_free(&query_string);
|
||||
DBUG_RETURN(ptr);
|
||||
@@ -1175,8 +1194,6 @@ get_options(int *argc,char ***argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (auto_generate_sql && num_of_query && auto_actual_queries)
|
||||
{
|
||||
fprintf(stderr,
|
||||
@@ -1217,6 +1234,7 @@ get_options(int *argc,char ***argv)
|
||||
num_int_cols= atoi(str->string);
|
||||
if (str->option)
|
||||
num_int_cols_index= atoi(str->option);
|
||||
|
||||
option_cleanup(str);
|
||||
}
|
||||
|
||||
@@ -1229,6 +1247,7 @@ get_options(int *argc,char ***argv)
|
||||
num_char_cols_index= atoi(str->option);
|
||||
else
|
||||
num_char_cols_index= 0;
|
||||
|
||||
option_cleanup(str);
|
||||
}
|
||||
|
||||
@@ -1463,6 +1482,7 @@ get_options(int *argc,char ***argv)
|
||||
|
||||
if (tty_password)
|
||||
opt_password= get_tty_password(NullS);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@@ -1477,6 +1497,7 @@ static int run_query(MYSQL *mysql, const char *query, int len)
|
||||
|
||||
if (verbose >= 3)
|
||||
printf("%.*s;\n", len, query);
|
||||
|
||||
return mysql_real_query(mysql, query, len);
|
||||
}
|
||||
|
||||
@@ -1592,18 +1613,6 @@ create_schema(MYSQL *mysql, const char *db, statement *stmt,
|
||||
}
|
||||
}
|
||||
|
||||
if (engine_stmt)
|
||||
{
|
||||
len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
|
||||
engine_stmt->string);
|
||||
if (run_query(mysql, query, len))
|
||||
{
|
||||
fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
|
||||
mysql_error(mysql));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
count= 0;
|
||||
after_create= stmt;
|
||||
|
||||
@@ -1617,8 +1626,21 @@ limit_not_met:
|
||||
{
|
||||
char buffer[HUGE_STRING_LENGTH];
|
||||
|
||||
snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string,
|
||||
engine_stmt->option);
|
||||
snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s %s",
|
||||
ptr->string, engine_stmt->string, engine_stmt->option);
|
||||
if (run_query(mysql, buffer, strlen(buffer)))
|
||||
{
|
||||
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
|
||||
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else if (engine_stmt && engine_stmt->string && ptr->type == CREATE_TABLE_TYPE)
|
||||
{
|
||||
char buffer[HUGE_STRING_LENGTH];
|
||||
|
||||
snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s",
|
||||
ptr->string, engine_stmt->string);
|
||||
if (run_query(mysql, buffer, strlen(buffer)))
|
||||
{
|
||||
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
|
||||
@@ -1652,6 +1674,7 @@ drop_schema(MYSQL *mysql, const char *db)
|
||||
{
|
||||
char query[HUGE_STRING_LENGTH];
|
||||
int len;
|
||||
|
||||
DBUG_ENTER("drop_schema");
|
||||
len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
|
||||
|
||||
@@ -1788,6 +1811,7 @@ pthread_handler_t run_task(void *p)
|
||||
my_progname, mysql_error(mysql));
|
||||
exit(0);
|
||||
}
|
||||
set_mysql_connect_options(mysql);
|
||||
|
||||
if (mysql_thread_init())
|
||||
{
|
||||
@@ -1828,7 +1852,6 @@ limit_not_met:
|
||||
my_progname, mysql_error(mysql));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (slap_connect(mysql))
|
||||
goto end;
|
||||
}
|
||||
@@ -1884,11 +1907,18 @@ limit_not_met:
|
||||
{
|
||||
if (mysql_field_count(mysql))
|
||||
{
|
||||
result= mysql_store_result(mysql);
|
||||
if ((result= mysql_store_result(mysql)))
|
||||
{
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
counter++;
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"%s: Error in mysql_store_result(): %d %s\n",
|
||||
my_progname, mysql_errno(mysql), mysql_error(mysql));
|
||||
}
|
||||
}
|
||||
} while(mysql_next_result(mysql) == 0);
|
||||
queries++;
|
||||
|
||||
@@ -1939,11 +1969,21 @@ parse_option(const char *origin, option_string **stmt, char delm)
|
||||
MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
|
||||
tmp= tmp->next)
|
||||
{
|
||||
char buffer[HUGE_STRING_LENGTH];
|
||||
/*
|
||||
Initialize buffer, because otherwise an
|
||||
--engine=<storage_engine>:<option>,<eng1>,<eng2>
|
||||
will crash.
|
||||
*/
|
||||
char buffer[HUGE_STRING_LENGTH]= "";
|
||||
char *buffer_ptr;
|
||||
|
||||
count++;
|
||||
strncpy(buffer, ptr, (size_t)(retstr - ptr));
|
||||
/*
|
||||
Handle --engine=memory:max_row=200 cases, or more general speaking
|
||||
--engine=<storage_engine>:<options>, which will be translated to
|
||||
Engine = storage_engine option.
|
||||
*/
|
||||
if ((buffer_ptr= strchr(buffer, ':')))
|
||||
{
|
||||
char *option_ptr;
|
||||
@@ -1964,9 +2004,11 @@ parse_option(const char *origin, option_string **stmt, char delm)
|
||||
tmp->length= (size_t)(retstr - ptr);
|
||||
}
|
||||
|
||||
/* Skip delimiter delm */
|
||||
ptr+= retstr - ptr + 1;
|
||||
if (isspace(*ptr))
|
||||
ptr++;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -1979,7 +2021,7 @@ parse_option(const char *origin, option_string **stmt, char delm)
|
||||
char *option_ptr;
|
||||
|
||||
tmp->length= (size_t)(origin_ptr - ptr);
|
||||
tmp->string= my_strndup(origin, tmp->length, MYF(MY_FAE));
|
||||
tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
|
||||
|
||||
option_ptr= (char *)ptr + 1 + tmp->length;
|
||||
|
||||
@@ -2087,6 +2129,7 @@ print_conclusions_csv(conclusions *con)
|
||||
{
|
||||
char buffer[HUGE_STRING_LENGTH];
|
||||
const char *ptr= auto_generate_sql_type ? auto_generate_sql_type : "query";
|
||||
|
||||
snprintf(buffer, HUGE_STRING_LENGTH,
|
||||
"%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
|
||||
con->engine ? con->engine : "", /* Storage engine we ran against */
|
||||
@@ -2173,6 +2216,7 @@ slap_connect(MYSQL *mysql)
|
||||
int x, connect_error= 1;
|
||||
for (x= 0; x < 10; x++)
|
||||
{
|
||||
set_mysql_connect_options(mysql);
|
||||
if (mysql_real_connect(mysql, host, user, opt_password,
|
||||
create_schema_string,
|
||||
opt_mysql_port,
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "client_priv.h"
|
||||
#include <mysql_version.h>
|
||||
#include <mysqld_error.h>
|
||||
#include <sql_common.h>
|
||||
#include <m_ctype.h>
|
||||
#include <my_dir.h>
|
||||
#include <hash.h>
|
||||
@@ -87,7 +88,8 @@ enum {
|
||||
OPT_PS_PROTOCOL=OPT_MAX_CLIENT_OPTION, OPT_SP_PROTOCOL,
|
||||
OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, OPT_MAX_CONNECT_RETRIES,
|
||||
OPT_MAX_CONNECTIONS, OPT_MARK_PROGRESS, OPT_LOG_DIR,
|
||||
OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION
|
||||
OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION,
|
||||
OPT_MY_CONNECT_TIMEOUT
|
||||
};
|
||||
|
||||
static int record= 0, opt_sleep= -1;
|
||||
@@ -101,6 +103,7 @@ static int opt_max_connect_retries;
|
||||
static int opt_result_format_version;
|
||||
static int opt_max_connections= DEFAULT_MAX_CONN;
|
||||
static my_bool opt_compress= 0, silent= 0, verbose= 0;
|
||||
static int opt_connect_timeout= -1;
|
||||
static my_bool debug_info_flag= 0, debug_check_flag= 0;
|
||||
static my_bool tty_password= 0;
|
||||
static my_bool opt_mark_progress= 0;
|
||||
@@ -114,6 +117,7 @@ static my_bool display_result_vertically= FALSE, display_result_lower= FALSE,
|
||||
static my_bool disable_query_log= 0, disable_result_log= 0;
|
||||
static my_bool disable_connect_log= 1;
|
||||
static my_bool disable_warnings= 0;
|
||||
static my_bool prepare_warnings_enabled= 0;
|
||||
static my_bool disable_info= 1;
|
||||
static my_bool abort_on_error= 1;
|
||||
static my_bool server_initialized= 0;
|
||||
@@ -134,6 +138,9 @@ static char delimiter[MAX_DELIMITER_LENGTH]= ";";
|
||||
static uint delimiter_length= 1;
|
||||
|
||||
static char TMPDIR[FN_REFLEN];
|
||||
static char global_subst_from[200];
|
||||
static char global_subst_to[200];
|
||||
static char *global_subst= NULL;
|
||||
|
||||
/* Block stack */
|
||||
enum block_cmd {
|
||||
@@ -200,6 +207,10 @@ static void init_re(void);
|
||||
static int match_re(my_regex_t *, char *);
|
||||
static void free_re(void);
|
||||
|
||||
static int replace(DYNAMIC_STRING *ds_str,
|
||||
const char *search_str, ulong search_len,
|
||||
const char *replace_str, ulong replace_len);
|
||||
|
||||
static uint opt_protocol=0;
|
||||
|
||||
DYNAMIC_ARRAY q_lines;
|
||||
@@ -311,6 +322,7 @@ enum enum_commands {
|
||||
Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
|
||||
Q_RESULT_FORMAT_VERSION,
|
||||
Q_MOVE_FILE, Q_REMOVE_FILES_WILDCARD, Q_SEND_EVAL,
|
||||
Q_ENABLE_PREPARE_WARNINGS, Q_DISABLE_PREPARE_WARNINGS,
|
||||
Q_UNKNOWN, /* Unknown command. */
|
||||
Q_COMMENT, /* Comments, ignored. */
|
||||
Q_COMMENT_WITH_COMMAND,
|
||||
@@ -411,6 +423,8 @@ const char *command_names[]=
|
||||
"move_file",
|
||||
"remove_files_wildcard",
|
||||
"send_eval",
|
||||
"enable_prepare_warnings",
|
||||
"disable_prepare_warnings",
|
||||
|
||||
0
|
||||
};
|
||||
@@ -543,7 +557,7 @@ public:
|
||||
{
|
||||
DBUG_ENTER("LogFile::open");
|
||||
DBUG_PRINT("enter", ("dir: '%s', name: '%s'",
|
||||
dir, name));
|
||||
val_or_null(dir), val_or_null(name)));
|
||||
if (!name)
|
||||
{
|
||||
m_file= stdout;
|
||||
@@ -609,14 +623,14 @@ public:
|
||||
lines++;
|
||||
|
||||
int show_offset= 0;
|
||||
char buf[256];
|
||||
char buf[256+1]; /* + zero termination for DBUG_PRINT */
|
||||
size_t bytes;
|
||||
bool found_bof= false;
|
||||
|
||||
/* Search backward in file until "lines" newline has been found */
|
||||
while (lines && !found_bof)
|
||||
{
|
||||
show_offset-= sizeof(buf);
|
||||
show_offset-= sizeof(buf)-1;
|
||||
while(fseek(m_file, show_offset, SEEK_END) != 0 && show_offset < 0)
|
||||
{
|
||||
found_bof= true;
|
||||
@@ -624,7 +638,7 @@ public:
|
||||
show_offset++;
|
||||
}
|
||||
|
||||
if ((bytes= fread(buf, 1, sizeof(buf), m_file)) <= 0)
|
||||
if ((bytes= fread(buf, 1, sizeof(buf)-1, m_file)) <= 0)
|
||||
{
|
||||
// ferror=0 will happen here if no queries executed yet
|
||||
if (ferror(m_file))
|
||||
@@ -634,6 +648,7 @@ public:
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
IF_DBUG(buf[bytes]= '\0';)
|
||||
DBUG_PRINT("info", ("Read %lu bytes from file, buf: %s",
|
||||
(unsigned long)bytes, buf));
|
||||
|
||||
@@ -678,8 +693,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
while ((bytes= fread(buf, 1, sizeof(buf), m_file)) > 0)
|
||||
fwrite(buf, 1, bytes, stderr);
|
||||
while ((bytes= fread(buf, 1, sizeof(buf)-1, m_file)) > 0)
|
||||
if (bytes != fwrite(buf, 1, bytes, stderr))
|
||||
die("Failed to write to '%s', errno: %d",
|
||||
m_file_name, errno);
|
||||
|
||||
if (!lines)
|
||||
{
|
||||
@@ -716,6 +733,10 @@ void handle_no_error(struct st_command*);
|
||||
#define EMB_READ_QUERY_RESULT 2
|
||||
#define EMB_END_CONNECTION 3
|
||||
|
||||
/* workaround for MySQL BUG#57491 */
|
||||
#undef MY_WME
|
||||
#define MY_WME 0
|
||||
|
||||
/* attributes of the query thread */
|
||||
pthread_attr_t cn_thd_attrib;
|
||||
|
||||
@@ -1152,7 +1173,8 @@ void check_command_args(struct st_command *command,
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void handle_command_error(struct st_command *command, uint error)
|
||||
void handle_command_error(struct st_command *command, uint error,
|
||||
int sys_errno)
|
||||
{
|
||||
DBUG_ENTER("handle_command_error");
|
||||
DBUG_PRINT("enter", ("error: %d", error));
|
||||
@@ -1168,13 +1190,14 @@ void handle_command_error(struct st_command *command, uint error)
|
||||
|
||||
if (i >= 0)
|
||||
{
|
||||
DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d",
|
||||
command->first_word_len, command->query, error));
|
||||
DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %u, errno: %d",
|
||||
command->first_word_len, command->query, error,
|
||||
sys_errno));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
if (command->expected_errors.count > 0)
|
||||
die("command \"%.*s\" failed with wrong error: %d",
|
||||
command->first_word_len, command->query, error);
|
||||
die("command \"%.*s\" failed with wrong error: %u, errno: %d",
|
||||
command->first_word_len, command->query, error, sys_errno);
|
||||
}
|
||||
else if (command->expected_errors.err[0].type == ERR_ERRNO &&
|
||||
command->expected_errors.err[0].code.errnum != 0)
|
||||
@@ -1317,15 +1340,6 @@ void die(const char *fmt, ...)
|
||||
DBUG_ENTER("die");
|
||||
DBUG_PRINT("enter", ("start_lineno: %d", start_lineno));
|
||||
|
||||
/*
|
||||
Protect against dying twice
|
||||
first time 'die' is called, try to write log files
|
||||
second time, just exit
|
||||
*/
|
||||
if (dying)
|
||||
cleanup_and_exit(1);
|
||||
dying= 1;
|
||||
|
||||
/* Print the error message */
|
||||
fprintf(stderr, "mysqltest: ");
|
||||
if (cur_file && cur_file != file_stack)
|
||||
@@ -1344,6 +1358,15 @@ void die(const char *fmt, ...)
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
|
||||
/*
|
||||
Protect against dying twice
|
||||
first time 'die' is called, try to write log files
|
||||
second time, just exit
|
||||
*/
|
||||
if (dying)
|
||||
cleanup_and_exit(1);
|
||||
dying= 1;
|
||||
|
||||
log_file.show_tail(opt_tail_lines);
|
||||
|
||||
/*
|
||||
@@ -1364,6 +1387,7 @@ void abort_not_supported_test(const char *fmt, ...)
|
||||
DBUG_ENTER("abort_not_supported_test");
|
||||
|
||||
/* Print include filestack */
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "The test '%s' is not supported by this installation\n",
|
||||
file_stack->file_name);
|
||||
fprintf(stderr, "Detected in file %s at line %d\n",
|
||||
@@ -1755,49 +1779,69 @@ enum compare_files_result_enum {
|
||||
|
||||
*/
|
||||
|
||||
int compare_files2(File fd, const char* filename2)
|
||||
int compare_files2(File fd1, const char* filename2)
|
||||
{
|
||||
int error= RESULT_OK;
|
||||
File fd2;
|
||||
size_t len, len2;
|
||||
char buff[512], buff2[512];
|
||||
size_t fd1_length, fd2_length;
|
||||
DYNAMIC_STRING fd1_result, fd2_result;
|
||||
|
||||
if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0)
|
||||
{
|
||||
my_close(fd, MYF(0));
|
||||
my_close(fd1, MYF(0));
|
||||
die("Failed to open second file: '%s'", filename2);
|
||||
}
|
||||
while((len= my_read(fd, (uchar*)&buff,
|
||||
sizeof(buff), MYF(0))) > 0)
|
||||
|
||||
fd1_length= (size_t) my_seek(fd1, 0, SEEK_END, MYF(0));
|
||||
fd2_length= (size_t) my_seek(fd2, 0, SEEK_END, MYF(0));
|
||||
|
||||
if (init_dynamic_string(&fd1_result, 0, fd1_length, 0) ||
|
||||
init_dynamic_string(&fd2_result, 0, fd2_length, 0))
|
||||
die("Out of memory when allocating data for result");
|
||||
|
||||
fd1_result.length= fd1_length;
|
||||
fd2_result.length= fd2_length;
|
||||
|
||||
(void) my_seek(fd1, 0, SEEK_SET, MYF(0));
|
||||
(void) my_seek(fd2, 0, SEEK_SET, MYF(0));
|
||||
if (my_read(fd1, (uchar*) fd1_result.str, fd1_length, MYF(MY_WME | MY_NABP)))
|
||||
die("Error when reading data from result file");
|
||||
if (my_read(fd2, (uchar*) fd2_result.str, fd2_length, MYF(MY_WME | MY_NABP)))
|
||||
die("Error when reading data from result file");
|
||||
|
||||
if (global_subst &&
|
||||
(fd1_length != fd2_length ||
|
||||
memcmp(fd1_result.str, fd2_result.str, fd1_length)))
|
||||
{
|
||||
if ((len2= my_read(fd2, (uchar*)&buff2,
|
||||
sizeof(buff2), MYF(0))) < len)
|
||||
{
|
||||
/* File 2 was smaller */
|
||||
error= RESULT_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
if (len2 > len)
|
||||
{
|
||||
/* File 1 was smaller */
|
||||
error= RESULT_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
if ((memcmp(buff, buff2, len)))
|
||||
{
|
||||
/* Content of this part differed */
|
||||
error= RESULT_CONTENT_MISMATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!error && my_read(fd2, (uchar*)&buff2,
|
||||
sizeof(buff2), MYF(0)) > 0)
|
||||
{
|
||||
/* File 1 was smaller */
|
||||
error= RESULT_LENGTH_MISMATCH;
|
||||
/**
|
||||
@todo MARIA_HACK
|
||||
This serves for when a test is run with --default-storage-engine=X
|
||||
where X is not MyISAM: tests using SHOW CREATE TABLE will always fail
|
||||
because SHOW CREATE TABLE prints X instead of MyISAM. With
|
||||
--global-subst=X,MyISAM , such trivial differences are eliminated and
|
||||
test may be reported as passing.
|
||||
--global-subst is only a quick way to run a lot of existing tests
|
||||
with Maria and find bugs; it is not good enough for reaching the main
|
||||
trees when Maria is merged into them.
|
||||
--global-subst should be removed.
|
||||
*/
|
||||
uint global_subst_from_len= strlen(global_subst_from);
|
||||
uint global_subst_to_len= strlen(global_subst_to);
|
||||
while (replace(&fd1_result,
|
||||
global_subst_from, global_subst_from_len,
|
||||
global_subst_to, global_subst_to_len) == 0)
|
||||
/* do nothing */ ;
|
||||
/* let's compare again to see if it is ok now */
|
||||
}
|
||||
|
||||
if (fd1_result.length != fd2_result.length)
|
||||
error= RESULT_LENGTH_MISMATCH;
|
||||
else if ((memcmp(fd1_result.str, fd2_result.str, fd1_result.length)))
|
||||
error= RESULT_CONTENT_MISMATCH;
|
||||
|
||||
my_close(fd2, MYF(0));
|
||||
dynstr_free(&fd1_result);
|
||||
dynstr_free(&fd2_result);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -1865,7 +1909,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
|
||||
{
|
||||
my_close(fd, MYF(0));
|
||||
/* Remove the temporary file */
|
||||
my_delete(temp_file_path, MYF(0));
|
||||
my_delete(temp_file_path, MYF(MY_WME));
|
||||
die("Failed to write file '%s'", temp_file_path);
|
||||
}
|
||||
|
||||
@@ -1873,7 +1917,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
|
||||
|
||||
my_close(fd, MYF(0));
|
||||
/* Remove the temporary file */
|
||||
my_delete(temp_file_path, MYF(0));
|
||||
my_delete(temp_file_path, MYF(MY_WME));
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@@ -1917,7 +1961,7 @@ void check_result()
|
||||
if (access(reject_file, W_OK) == 0)
|
||||
{
|
||||
/* Result file directory is writable, save reject file there */
|
||||
fn_format(reject_file, result_file_name, NULL,
|
||||
fn_format(reject_file, result_file_name, "",
|
||||
".reject", MY_REPLACE_EXT);
|
||||
}
|
||||
else
|
||||
@@ -3090,8 +3134,8 @@ void do_remove_file(struct st_command *command)
|
||||
' ');
|
||||
|
||||
DBUG_PRINT("info", ("removing file: %s", ds_filename.str));
|
||||
error= my_delete(ds_filename.str, MYF(0)) != 0;
|
||||
handle_command_error(command, error);
|
||||
error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0;
|
||||
handle_command_error(command, error, my_errno);
|
||||
dynstr_free(&ds_filename);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -3109,7 +3153,7 @@ void do_remove_file(struct st_command *command)
|
||||
|
||||
void do_remove_files_wildcard(struct st_command *command)
|
||||
{
|
||||
int error= 0;
|
||||
int error= 0, sys_errno= 0;
|
||||
uint i;
|
||||
MY_DIR *dir_info;
|
||||
FILEINFO *file;
|
||||
@@ -3133,9 +3177,10 @@ void do_remove_files_wildcard(struct st_command *command)
|
||||
|
||||
DBUG_PRINT("info", ("listing directory: %s", dirname));
|
||||
/* Note that my_dir sorts the list if not given any flags */
|
||||
if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT))))
|
||||
if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT | MY_WME))))
|
||||
{
|
||||
error= 1;
|
||||
sys_errno= my_errno;
|
||||
goto end;
|
||||
}
|
||||
init_dynamic_string(&ds_file_to_remove, dirname, 1024, 1024);
|
||||
@@ -3161,7 +3206,8 @@ void do_remove_files_wildcard(struct st_command *command)
|
||||
ds_file_to_remove.str[ds_directory.length + 1]= 0;
|
||||
dynstr_append(&ds_file_to_remove, file->name);
|
||||
DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str));
|
||||
error= my_delete(ds_file_to_remove.str, MYF(0)) != 0;
|
||||
if ((error= (my_delete(ds_file_to_remove.str, MYF(MY_WME)) != 0)))
|
||||
sys_errno= my_errno;
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
@@ -3169,7 +3215,7 @@ void do_remove_files_wildcard(struct st_command *command)
|
||||
my_dirend(dir_info);
|
||||
|
||||
end:
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, sys_errno);
|
||||
dynstr_free(&ds_directory);
|
||||
dynstr_free(&ds_wild);
|
||||
dynstr_free(&ds_file_to_remove);
|
||||
@@ -3207,8 +3253,8 @@ void do_copy_file(struct st_command *command)
|
||||
|
||||
DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str));
|
||||
error= (my_copy(ds_from_file.str, ds_to_file.str,
|
||||
MYF(MY_DONT_OVERWRITE_FILE)) != 0);
|
||||
handle_command_error(command, error);
|
||||
MYF(MY_DONT_OVERWRITE_FILE | MY_WME)) != 0);
|
||||
handle_command_error(command, error, my_errno);
|
||||
dynstr_free(&ds_from_file);
|
||||
dynstr_free(&ds_to_file);
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -3243,8 +3289,8 @@ void do_move_file(struct st_command *command)
|
||||
|
||||
DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str));
|
||||
error= (my_rename(ds_from_file.str, ds_to_file.str,
|
||||
MYF(0)) != 0);
|
||||
handle_command_error(command, error);
|
||||
MYF(disable_warnings ? 0 : MY_WME)) != 0);
|
||||
handle_command_error(command, error, my_errno);
|
||||
dynstr_free(&ds_from_file);
|
||||
dynstr_free(&ds_to_file);
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -3288,7 +3334,7 @@ void do_chmod_file(struct st_command *command)
|
||||
err_code= chmod(ds_file.str, mode);
|
||||
if (err_code < 0)
|
||||
err_code= 1;
|
||||
handle_command_error(command, err_code);
|
||||
handle_command_error(command, err_code, errno);
|
||||
dynstr_free(&ds_mode);
|
||||
dynstr_free(&ds_file);
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -3321,7 +3367,7 @@ void do_file_exist(struct st_command *command)
|
||||
|
||||
DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str));
|
||||
error= (access(ds_filename.str, F_OK) != 0);
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, errno);
|
||||
dynstr_free(&ds_filename);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -3351,8 +3397,8 @@ void do_mkdir(struct st_command *command)
|
||||
' ');
|
||||
|
||||
DBUG_PRINT("info", ("creating directory: %s", ds_dirname.str));
|
||||
error= my_mkdir(ds_dirname.str, 0777, MYF(0)) != 0;
|
||||
handle_command_error(command, error);
|
||||
error= my_mkdir(ds_dirname.str, 0777, MYF(MY_WME)) != 0;
|
||||
handle_command_error(command, error, my_errno);
|
||||
dynstr_free(&ds_dirname);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -3382,7 +3428,7 @@ void do_rmdir(struct st_command *command)
|
||||
|
||||
DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str));
|
||||
error= rmdir(ds_dirname.str) != 0;
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, errno);
|
||||
dynstr_free(&ds_dirname);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -3458,7 +3504,7 @@ static void do_list_files(struct st_command *command)
|
||||
sizeof(list_files_args)/sizeof(struct command_arg), ' ');
|
||||
|
||||
error= get_list_files(&ds_res, &ds_dirname, &ds_wild);
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, my_errno);
|
||||
dynstr_free(&ds_dirname);
|
||||
dynstr_free(&ds_wild);
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -3500,7 +3546,7 @@ static void do_list_files_write_file_command(struct st_command *command,
|
||||
|
||||
init_dynamic_string(&ds_content, "", 1024, 1024);
|
||||
error= get_list_files(&ds_content, &ds_dirname, &ds_wild);
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, my_errno);
|
||||
str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append);
|
||||
dynstr_free(&ds_content);
|
||||
dynstr_free(&ds_filename);
|
||||
@@ -3724,7 +3770,7 @@ void do_cat_file(struct st_command *command)
|
||||
DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str));
|
||||
|
||||
error= cat_file(&ds_res, ds_filename.str);
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, my_errno);
|
||||
dynstr_free(&ds_filename);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -3770,7 +3816,8 @@ void do_diff_files(struct st_command *command)
|
||||
if ((error= compare_files(ds_filename.str, ds_filename2.str)) &&
|
||||
match_expected_error(command, error, NULL) < 0)
|
||||
{
|
||||
/* Compare of the two files failed, append them to output
|
||||
/*
|
||||
Compare of the two files failed, append them to output
|
||||
so the failure can be analyzed, but only if it was not
|
||||
expected to fail.
|
||||
*/
|
||||
@@ -3782,7 +3829,7 @@ void do_diff_files(struct st_command *command)
|
||||
|
||||
dynstr_free(&ds_filename);
|
||||
dynstr_free(&ds_filename2);
|
||||
handle_command_error(command, error);
|
||||
handle_command_error(command, error, -1);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -3878,6 +3925,7 @@ void do_change_user(struct st_command *command)
|
||||
}
|
||||
|
||||
if (!ds_user.length)
|
||||
{
|
||||
dynstr_set(&ds_user, mysql->user);
|
||||
|
||||
if (!ds_passwd.length)
|
||||
@@ -3885,6 +3933,7 @@ void do_change_user(struct st_command *command)
|
||||
|
||||
if (!ds_db.length)
|
||||
dynstr_set(&ds_db, mysql->db);
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("connection: '%s' user: '%s' password: '%s' database: '%s'",
|
||||
cur_con->name, ds_user.str, ds_passwd.str, ds_db.str));
|
||||
@@ -3988,7 +4037,7 @@ void do_perl(struct st_command *command)
|
||||
|
||||
/* Remove the temporary file, but keep it if perl failed */
|
||||
if (!error)
|
||||
my_delete(temp_file_path, MYF(0));
|
||||
my_delete(temp_file_path, MYF(MY_WME));
|
||||
|
||||
/* Check for error code that indicates perl could not be started */
|
||||
int exstat= WEXITSTATUS(error);
|
||||
@@ -4001,7 +4050,7 @@ void do_perl(struct st_command *command)
|
||||
abort_not_supported_test("perl not found in path");
|
||||
#endif
|
||||
else
|
||||
handle_command_error(command, exstat);
|
||||
handle_command_error(command, exstat, my_errno);
|
||||
}
|
||||
dynstr_free(&ds_delimiter);
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -4875,11 +4924,11 @@ char *get_string(char **to_ptr, char **from_ptr,
|
||||
}
|
||||
|
||||
|
||||
void set_reconnect(MYSQL* mysql, int val)
|
||||
void set_reconnect(MYSQL* mysql, my_bool val)
|
||||
{
|
||||
my_bool reconnect= val;
|
||||
DBUG_ENTER("set_reconnect");
|
||||
DBUG_PRINT("info", ("val: %d", val));
|
||||
DBUG_PRINT("info", ("val: %d", (int) val));
|
||||
#if MYSQL_VERSION_ID < 50000
|
||||
mysql->reconnect= reconnect;
|
||||
#else
|
||||
@@ -4949,7 +4998,7 @@ void select_connection(struct st_command *command)
|
||||
|
||||
void do_close_connection(struct st_command *command)
|
||||
{
|
||||
DBUG_ENTER("close_connection");
|
||||
DBUG_ENTER("do_close_connection");
|
||||
|
||||
struct st_connection *con;
|
||||
static DYNAMIC_STRING ds_connection;
|
||||
@@ -5022,6 +5071,7 @@ void do_close_connection(struct st_command *command)
|
||||
dynstr_append_mem(ds, ";\n", 2);
|
||||
}
|
||||
|
||||
dynstr_free(&ds_connection);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -5314,6 +5364,7 @@ void do_connect(struct st_command *command)
|
||||
con_options= ds_options.str;
|
||||
while (*con_options)
|
||||
{
|
||||
size_t length;
|
||||
char *end;
|
||||
/* Step past any spaces in beginning of option*/
|
||||
while (*con_options && my_isspace(charset_info, *con_options))
|
||||
@@ -5322,13 +5373,14 @@ void do_connect(struct st_command *command)
|
||||
end= con_options;
|
||||
while (*end && !my_isspace(charset_info, *end))
|
||||
end++;
|
||||
if (!strncmp(con_options, "SSL", 3))
|
||||
length= (size_t) (end - con_options);
|
||||
if (length == 3 && !strncmp(con_options, "SSL", 3))
|
||||
con_ssl= 1;
|
||||
else if (!strncmp(con_options, "COMPRESS", 8))
|
||||
else if (length == 8 && !strncmp(con_options, "COMPRESS", 8))
|
||||
con_compress= 1;
|
||||
else if (!strncmp(con_options, "PIPE", 4))
|
||||
else if (length == 4 && !strncmp(con_options, "PIPE", 4))
|
||||
con_pipe= 1;
|
||||
else if (!strncmp(con_options, "SHM", 3))
|
||||
else if (length == 3 && !strncmp(con_options, "SHM", 3))
|
||||
con_shm= 1;
|
||||
else
|
||||
die("Illegal option to connect: %.*s",
|
||||
@@ -5368,6 +5420,9 @@ void do_connect(struct st_command *command)
|
||||
if (opt_charsets_dir)
|
||||
mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_DIR,
|
||||
opt_charsets_dir);
|
||||
if (opt_connect_timeout >= 0)
|
||||
mysql_options(&con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
|
||||
&opt_connect_timeout);
|
||||
|
||||
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
|
||||
if (opt_use_ssl || con_ssl)
|
||||
@@ -5409,7 +5464,6 @@ void do_connect(struct st_command *command)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Use default db name */
|
||||
if (ds_database.length == 0)
|
||||
dynstr_set(&ds_database, opt_db);
|
||||
@@ -6195,6 +6249,9 @@ static struct my_option my_long_options[] =
|
||||
GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
|
||||
{"test-file", 'x', "Read test from/in this file (default stdin).",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"connect-timeout", OPT_MY_CONNECT_TIMEOUT, "Client connection timeout",
|
||||
(uchar**) &opt_connect_timeout, (uchar**) &opt_connect_timeout, 0,
|
||||
GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0},
|
||||
{"timer-file", 'm', "File where the timing in microseconds is stored.",
|
||||
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"tmpdir", 't', "Temporary directory where sockets are put.",
|
||||
@@ -6406,6 +6463,15 @@ int parse_args(int argc, char **argv)
|
||||
if (debug_check_flag)
|
||||
my_end_arg= MY_CHECK_ERROR;
|
||||
|
||||
if (global_subst != NULL)
|
||||
{
|
||||
char *comma= strstr(global_subst, ",");
|
||||
if (comma == NULL)
|
||||
die("wrong --global-subst, must be X,Y");
|
||||
memcpy(global_subst_from, global_subst, (comma-global_subst));
|
||||
global_subst_from[comma-global_subst]= 0;
|
||||
memcpy(global_subst_to, comma+1, strlen(comma));
|
||||
}
|
||||
|
||||
if (!record)
|
||||
{
|
||||
@@ -7345,7 +7411,16 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command,
|
||||
|
||||
mysql_free_result(res); /* Free normal result set with meta data */
|
||||
|
||||
/* Clear prepare warnings */
|
||||
/*
|
||||
Normally, if there is a result set, we do not show warnings from the
|
||||
prepare phase. This is because some warnings are generated both during
|
||||
prepare and execute; this would generate different warning output
|
||||
between normal and ps-protocol test runs.
|
||||
|
||||
The --enable_prepare_warnings command can be used to change this so
|
||||
that warnings from both the prepare and execute phase are shown.
|
||||
*/
|
||||
if (!disable_warnings && !prepare_warnings_enabled)
|
||||
dynstr_set(&ds_prepare_warnings, NULL);
|
||||
}
|
||||
else
|
||||
@@ -7359,7 +7434,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command,
|
||||
Fetch info before fetching warnings, since it will be reset
|
||||
otherwise.
|
||||
*/
|
||||
|
||||
if (!disable_info)
|
||||
append_info(ds, mysql_stmt_affected_rows(stmt), mysql_info(mysql));
|
||||
|
||||
@@ -7394,14 +7468,6 @@ end:
|
||||
dynstr_free(&ds_execute_warnings);
|
||||
}
|
||||
|
||||
|
||||
/* Close the statement if - no reconnect, need new prepare */
|
||||
if (mysql->reconnect)
|
||||
{
|
||||
mysql_stmt_close(stmt);
|
||||
cur_con->stmt= NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
We save the return code (mysql_stmt_errno(stmt)) from the last call sent
|
||||
to the server into the mysqltest builtin variable $mysql_errno. This
|
||||
@@ -7410,6 +7476,13 @@ end:
|
||||
|
||||
var_set_errno(mysql_stmt_errno(stmt));
|
||||
|
||||
/* Close the statement if reconnect, need new prepare */
|
||||
if (mysql->reconnect)
|
||||
{
|
||||
mysql_stmt_close(stmt);
|
||||
cur_con->stmt= NULL;
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -7571,7 +7644,6 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
|
||||
}
|
||||
|
||||
dynstr_free(&query_str);
|
||||
|
||||
}
|
||||
|
||||
if (sp_protocol_enabled &&
|
||||
@@ -7856,7 +7928,7 @@ void mark_progress(struct st_command* command __attribute__((unused)),
|
||||
die("Out of memory");
|
||||
|
||||
/* Milliseconds since start */
|
||||
end= longlong2str(timer, buf, 10);
|
||||
end= longlong10_to_str(timer, buf, 10);
|
||||
dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
|
||||
dynstr_append_mem(&ds_progress, "\t", 1);
|
||||
|
||||
@@ -7984,7 +8056,6 @@ static void init_signal_handling(void)
|
||||
#endif
|
||||
sigaction(SIGILL, &sa, NULL);
|
||||
sigaction(SIGFPE, &sa, NULL);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -7996,6 +8067,7 @@ int main(int argc, char **argv)
|
||||
my_bool q_send_flag= 0, abort_flag= 0;
|
||||
uint command_executed= 0, last_command_executed= 0;
|
||||
char save_file[FN_REFLEN];
|
||||
bool empty_result= FALSE;
|
||||
MY_INIT(argv[0]);
|
||||
|
||||
save_file[0]= 0;
|
||||
@@ -8171,6 +8243,7 @@ int main(int argc, char **argv)
|
||||
verbose_msg("Start processing test commands from '%s' ...", cur_file->file_name);
|
||||
while (!read_command(&command) && !abort_flag)
|
||||
{
|
||||
my_bool ok_to_do;
|
||||
int current_line_inc = 1, processed = 0;
|
||||
if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
|
||||
get_command_type(command);
|
||||
@@ -8188,7 +8261,7 @@ int main(int argc, char **argv)
|
||||
abort_on_error);
|
||||
|
||||
/* delimiter needs to be executed so we can continue to parse */
|
||||
my_bool ok_to_do= cur_block->ok || command->type == Q_DELIMITER;
|
||||
ok_to_do= cur_block->ok || command->type == Q_DELIMITER;
|
||||
/*
|
||||
Some commands need to be "done" the first time if they may get
|
||||
re-iterated over in a true context. This can only happen if there's
|
||||
@@ -8235,6 +8308,8 @@ int main(int argc, char **argv)
|
||||
case Q_DISABLE_CONNECT_LOG: disable_connect_log=1; break;
|
||||
case Q_ENABLE_WARNINGS: disable_warnings=0; break;
|
||||
case Q_DISABLE_WARNINGS: disable_warnings=1; break;
|
||||
case Q_ENABLE_PREPARE_WARNINGS: prepare_warnings_enabled=1; break;
|
||||
case Q_DISABLE_PREPARE_WARNINGS: prepare_warnings_enabled=0; break;
|
||||
case Q_ENABLE_INFO: disable_info=0; break;
|
||||
case Q_DISABLE_INFO: disable_info=1; break;
|
||||
case Q_ENABLE_METADATA: display_metadata=1; break;
|
||||
@@ -8427,12 +8502,12 @@ int main(int argc, char **argv)
|
||||
dynstr_append(&ds_res, "\n");
|
||||
break;
|
||||
case Q_PING:
|
||||
handle_command_error(command, mysql_ping(&cur_con->mysql));
|
||||
handle_command_error(command, mysql_ping(&cur_con->mysql), -1);
|
||||
break;
|
||||
case Q_SEND_SHUTDOWN:
|
||||
handle_command_error(command,
|
||||
mysql_shutdown(&cur_con->mysql,
|
||||
SHUTDOWN_DEFAULT));
|
||||
SHUTDOWN_DEFAULT), -1);
|
||||
break;
|
||||
case Q_SHUTDOWN_SERVER:
|
||||
do_shutdown_server(command);
|
||||
@@ -8493,7 +8568,10 @@ int main(int argc, char **argv)
|
||||
abort_flag= 1;
|
||||
break;
|
||||
case Q_SKIP:
|
||||
abort_not_supported_test("%s", command->first_argument);
|
||||
/* Eval the query, thus replacing all environment variables */
|
||||
dynstr_set(&ds_res, 0);
|
||||
do_eval(&ds_res, command->first_argument, command->end, FALSE);
|
||||
abort_not_supported_test("%s",ds_res.str);
|
||||
break;
|
||||
|
||||
case Q_RESULT:
|
||||
@@ -8561,8 +8639,6 @@ int main(int argc, char **argv)
|
||||
if (parsing_disabled)
|
||||
die("Test ended with parsing disabled");
|
||||
|
||||
my_bool empty_result= FALSE;
|
||||
|
||||
/*
|
||||
The whole test has been executed _sucessfully_.
|
||||
Time to compare result or save it to record file.
|
||||
@@ -8643,7 +8719,7 @@ void timer_output(void)
|
||||
{
|
||||
char buf[32], *end;
|
||||
ulonglong timer= timer_now() - timer_start;
|
||||
end= longlong2str(timer, buf, 10);
|
||||
end= longlong10_to_str(timer, buf, 10);
|
||||
str_to_file(timer_file,buf, (int) (end-buf));
|
||||
/* Timer has been written to the file, don't use it anymore */
|
||||
timer_file= 0;
|
||||
@@ -8802,15 +8878,15 @@ void free_replace()
|
||||
|
||||
|
||||
typedef struct st_replace {
|
||||
my_bool found;
|
||||
int found;
|
||||
struct st_replace *next[256];
|
||||
} REPLACE;
|
||||
|
||||
typedef struct st_replace_found {
|
||||
my_bool found;
|
||||
char *replace_string;
|
||||
int found;
|
||||
uint to_offset;
|
||||
int from_offset;
|
||||
char *replace_string;
|
||||
} REPLACE_STRING;
|
||||
|
||||
|
||||
@@ -8842,7 +8918,7 @@ void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds,
|
||||
}
|
||||
|
||||
/* Found a string that needs to be replaced */
|
||||
DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s",
|
||||
DBUG_PRINT("info", ("found: %d, to_offset: %u, from_offset: %d, string: %s",
|
||||
rep_str->found, rep_str->to_offset,
|
||||
rep_str->from_offset, rep_str->replace_string));
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
/* This file is originally from the mysql distribution. Coded by monty */
|
||||
|
||||
#ifndef CLIENT_SQL_STRING_H
|
||||
#define CLIENT_SQL_STRING_H
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
@@ -59,8 +59,8 @@
|
||||
#define largest_char 255 /* Largest character value. */
|
||||
|
||||
#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
|
||||
#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
|
||||
#define META_CHAR_FOR_UCHAR(c) ((c) > meta_character_threshold)
|
||||
#define META_CHAR(c) (META_CHAR_FOR_UCHAR(c) && (c) <= largest_char)
|
||||
|
||||
#define CTRL(c) ((c) & control_character_mask)
|
||||
#define META(c) ((c) | meta_character_bit)
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef NOT_YET /* causes problem on MacOSX */
|
||||
/* to get wcwidth() defined */
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _XOPEN_SOURCE_EXTENDED
|
||||
#define _XOPEN_
|
||||
#endif
|
||||
|
||||
/*
|
||||
Ultrix botches type-ahead when switching from canonical to
|
||||
non-canonical mode, at least through version 4.3
|
||||
|
||||
@@ -191,8 +191,6 @@ static int visible_first_line_len;
|
||||
(or is equal to) _rl_screenwidth. */
|
||||
static int prompt_invis_chars_first_line;
|
||||
|
||||
static int prompt_last_screen_line;
|
||||
|
||||
static int prompt_physical_chars;
|
||||
|
||||
/* Variables to save and restore prompt and display information. */
|
||||
@@ -461,7 +459,7 @@ rl_redisplay ()
|
||||
{
|
||||
register int in, out, c, linenum, cursor_linenum;
|
||||
register char *line;
|
||||
int inv_botlin, lb_botlin, lb_linenum, o_cpos;
|
||||
int inv_botlin, lb_linenum, o_cpos;
|
||||
int newlines, lpos, temp, modmark;
|
||||
const char *prompt_this_line;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
@@ -675,11 +673,9 @@ rl_redisplay ()
|
||||
lpos -= _rl_screenwidth;
|
||||
}
|
||||
|
||||
prompt_last_screen_line = newlines;
|
||||
|
||||
/* Draw the rest of the line (after the prompt) into invisible_line, keeping
|
||||
track of where the cursor is (cpos_buffer_position), the number of the line containing
|
||||
the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
|
||||
the cursor (lb_linenum), the last line number (inv_botlin).
|
||||
It maintains an array of line breaks for display (inv_lbreaks).
|
||||
This handles expanding tabs for display and displaying meta characters. */
|
||||
lb_linenum = 0;
|
||||
@@ -862,7 +858,7 @@ rl_redisplay ()
|
||||
lb_linenum = newlines;
|
||||
}
|
||||
|
||||
inv_botlin = lb_botlin = newlines;
|
||||
inv_botlin = newlines;
|
||||
CHECK_INV_LBREAKS ();
|
||||
inv_lbreaks[newlines+1] = out;
|
||||
cursor_linenum = lb_linenum;
|
||||
|
||||
@@ -693,7 +693,7 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
|
||||
case 's':
|
||||
{
|
||||
char *new_event;
|
||||
int delimiter, failed, si, l_temp, ws, we;
|
||||
int delimiter, failed, si, l_temp, we;
|
||||
|
||||
if (c == 's')
|
||||
{
|
||||
@@ -792,7 +792,6 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
|
||||
{
|
||||
for (; temp[si] && whitespace (temp[si]); si++)
|
||||
;
|
||||
ws = si;
|
||||
we = history_tokenize_word (temp, si);
|
||||
}
|
||||
|
||||
|
||||
@@ -211,14 +211,14 @@ history_get (offset)
|
||||
|
||||
HIST_ENTRY *
|
||||
alloc_history_entry (string, ts)
|
||||
char *string;
|
||||
const char *string;
|
||||
char *ts;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
|
||||
|
||||
temp->line = string ? savestring (string) : string;
|
||||
temp->line = string ? savestring ((char*) string) : (char*) string;
|
||||
temp->data = (char *)NULL;
|
||||
temp->timestamp = ts;
|
||||
|
||||
@@ -306,7 +306,7 @@ add_history (string)
|
||||
}
|
||||
}
|
||||
|
||||
temp = alloc_history_entry (string, hist_inittime ());
|
||||
temp = alloc_history_entry ((char*) string, hist_inittime ());
|
||||
|
||||
the_history[history_length] = (HIST_ENTRY *)NULL;
|
||||
the_history[history_length - 1] = temp;
|
||||
|
||||
@@ -90,7 +90,6 @@ static void bind_arrow_keys_internal PARAMS((Keymap));
|
||||
static void bind_arrow_keys PARAMS((void));
|
||||
|
||||
static void readline_default_bindings PARAMS((void));
|
||||
static void reset_default_bindings PARAMS((void)) __attribute__((unused));
|
||||
|
||||
static int _rl_subseq_result PARAMS((int, Keymap, int, int));
|
||||
static int _rl_subseq_getchar PARAMS((int));
|
||||
@@ -287,7 +286,7 @@ rl_set_prompt (prompt)
|
||||
{
|
||||
FREE (rl_prompt);
|
||||
rl_prompt = prompt ? savestring (prompt) : (char *)NULL;
|
||||
rl_display_prompt = rl_prompt ? rl_prompt : "";
|
||||
rl_display_prompt = rl_prompt ? rl_prompt : (char*) "";
|
||||
|
||||
rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
|
||||
return 0;
|
||||
@@ -1072,18 +1071,6 @@ readline_default_bindings ()
|
||||
rl_tty_set_default_bindings (_rl_keymap);
|
||||
}
|
||||
|
||||
/* Reset the default bindings for the terminal special characters we're
|
||||
interested in back to rl_insert and read the new ones. */
|
||||
static void
|
||||
reset_default_bindings ()
|
||||
{
|
||||
if (_rl_bind_stty_chars)
|
||||
{
|
||||
rl_tty_unset_default_bindings (_rl_keymap);
|
||||
rl_tty_set_default_bindings (_rl_keymap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bind some common arrow key sequences in MAP. */
|
||||
static void
|
||||
bind_arrow_keys_internal (map)
|
||||
|
||||
@@ -1169,7 +1169,7 @@ rl_insert_comment (count, key)
|
||||
int rl_comment_len;
|
||||
|
||||
rl_beg_of_line (1, key);
|
||||
rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT;
|
||||
rl_comment_text = _rl_comment_begin ? _rl_comment_begin : (char*) RL_COMMENT_BEGIN_DEFAULT;
|
||||
|
||||
if (rl_explicit_arg == 0)
|
||||
rl_insert_text (rl_comment_text);
|
||||
@@ -1386,10 +1386,11 @@ rl_transpose_chars (count, key)
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
char *dummy;
|
||||
int i;
|
||||
int prev_point;
|
||||
#else
|
||||
char dummy[2];
|
||||
#endif
|
||||
int char_length, prev_point;
|
||||
int char_length;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
@@ -1408,7 +1409,9 @@ rl_transpose_chars (count, key)
|
||||
count = 1;
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
prev_point = rl_point;
|
||||
#endif
|
||||
rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
static void
|
||||
memory_error_and_abort (fname)
|
||||
char *fname;
|
||||
const char *fname;
|
||||
{
|
||||
fprintf (stderr, "%s: out of virtual memory\n", fname);
|
||||
exit (2);
|
||||
|
||||
95
config/ac-macros/libevent.m4
Normal file
95
config/ac-macros/libevent.m4
Normal file
@@ -0,0 +1,95 @@
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Macro: MYSQL_USE_BUNDLED_LIBEVENT
|
||||
dnl
|
||||
dnl SYNOPSIS
|
||||
dnl MYSQL_USE_BUNDLED_LIBEVENT()
|
||||
dnl
|
||||
dnl DESCRIPTION
|
||||
dnl Add defines so libevent is built and linked with
|
||||
dnl ---------------------------------------------------------------------------
|
||||
AC_DEFUN([MYSQL_USE_BUNDLED_LIBEVENT], [
|
||||
|
||||
libevent_dir="libevent"
|
||||
AC_SUBST([libevent_dir])
|
||||
|
||||
libevent_libs="\$(top_builddir)/extra/libevent/libevent.a"
|
||||
libevent_includes="-I\$(top_srcdir)/extra/libevent"
|
||||
|
||||
dnl Get the upstream file with the original libevent configure macros.
|
||||
dnl Use builtin include for this, to work around path problems in old versions of aclocal.
|
||||
builtin([include],[config/ac-macros/libevent_configure.m4])
|
||||
])
|
||||
|
||||
|
||||
dnl ------------------------------------------------------------------------
|
||||
dnl Macro: MYSQL_CHECK_LIBEVENT
|
||||
dnl
|
||||
dnl SYNOPSIS
|
||||
dnl MYSQL_CHECK_LIBEVENT
|
||||
dnl
|
||||
dnl ------------------------------------------------------------------------
|
||||
AC_DEFUN([MYSQL_CHECK_LIBEVENT], [
|
||||
|
||||
AC_CONFIG_FILES(extra/libevent/Makefile)
|
||||
|
||||
AC_MSG_NOTICE([checking what libevent library to use])
|
||||
|
||||
AC_ARG_WITH([libevent],
|
||||
AC_HELP_STRING([--with-libevent=yes|no|bundled|DIR],
|
||||
[Use libevent and have connection pooling.
|
||||
A location of libevent library can be specified.
|
||||
Given DIR, libevent library is
|
||||
assumed to be in $DIR/lib and header files
|
||||
in $DIR/include.]),
|
||||
[with_libevent=${withval}],
|
||||
[with_libevent=no])
|
||||
|
||||
case "$with_libevent" in
|
||||
"no")
|
||||
with_libevent=disabled
|
||||
;;
|
||||
"bundled")
|
||||
MYSQL_USE_BUNDLED_LIBEVENT
|
||||
;;
|
||||
"" | "yes")
|
||||
libevent_includes=""
|
||||
libevent_libs="-levent"
|
||||
AC_CHECK_LIB(event, evutil_socketpair,[with_libevent=system],
|
||||
[with_libevent=bundled])
|
||||
AC_CHECK_HEADER(evutil.h,,[with_libevent=bundled])
|
||||
if test "$with_libevent" = "bundled"; then
|
||||
MYSQL_USE_BUNDLED_LIBEVENT
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Test for libevent using all known library file endings
|
||||
if test \( -f "$with_libevent/lib/libevent.a" -o \
|
||||
-f "$with_libevent/lib/libevent.so" -o \
|
||||
-f "$with_libevent/lib/libevent.sl" -o \
|
||||
-f "$with_libevent/lib/libevent.dylib" \) \
|
||||
-a -f "$with_libevent/include/evutil.h"; then
|
||||
libevent_includes="-I$with_libevent/include"
|
||||
libevent_libs="-L$with_libevent/lib -levent"
|
||||
AC_CHECK_LIB(event, evutil_socketpair,[with_libevent=$with_libevent],
|
||||
[with_libevent=no], [$libevent_libs])
|
||||
else
|
||||
with_libevent=no
|
||||
fi
|
||||
if test "$with_libevent" = "no"; then
|
||||
AC_MSG_ERROR([libevent headers or binaries were not found])
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_CHECKING(for libevent)
|
||||
AC_MSG_RESULT([$with_libevent])
|
||||
|
||||
if test "$with_libevent" != "disabled"; then
|
||||
libevent_test_option="--mysqld=--thread-handling=pool-of-threads"
|
||||
AC_SUBST(libevent_libs)
|
||||
AC_SUBST(libevent_includes)
|
||||
AC_SUBST(libevent_test_option)
|
||||
AC_DEFINE([HAVE_LIBEVENT], [1], [If we want to use libevent and have connection pooling])
|
||||
fi
|
||||
AM_CONDITIONAL([HAVE_LIBEVENT], [ test "$with_libevent" != "disabled" ])
|
||||
])
|
||||
|
||||
324
config/ac-macros/libevent_configure.m4
Normal file
324
config/ac-macros/libevent_configure.m4
Normal file
@@ -0,0 +1,324 @@
|
||||
dnl Checks for libraries.
|
||||
AC_CHECK_LIB(socket, socket)
|
||||
AC_CHECK_LIB(resolv, inet_aton)
|
||||
AC_CHECK_LIB(rt, clock_gettime)
|
||||
AC_CHECK_LIB(nsl, inet_ntoa)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h)
|
||||
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
|
||||
|
||||
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(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop signal sigaction strtoll)
|
||||
|
||||
AC_CHECK_SIZEOF(long)
|
||||
|
||||
if test "x$ac_cv_func_clock_gettime" = "xyes"; then
|
||||
AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc])
|
||||
else
|
||||
AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available])
|
||||
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
|
||||
AC_CHECK_FUNCS(select, [haveselect=yes])
|
||||
if test "x$haveselect" = "xyes" ; then
|
||||
AC_LIBOBJ(select)
|
||||
needsignal=yes
|
||||
fi
|
||||
|
||||
havepoll=no
|
||||
AC_CHECK_FUNCS(poll, [havepoll=yes])
|
||||
if test "x$havepoll" = "xyes" ; then
|
||||
AC_LIBOBJ(poll)
|
||||
needsignal=yes
|
||||
fi
|
||||
|
||||
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])
|
||||
AC_LIBOBJ(epoll)
|
||||
needsignal=yes
|
||||
fi
|
||||
|
||||
havedevpoll=no
|
||||
if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
|
||||
AC_DEFINE(HAVE_DEVPOLL, 1,
|
||||
[Define if /dev/poll is available])
|
||||
AC_LIBOBJ(devpoll)
|
||||
fi
|
||||
|
||||
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_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/event.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
]],
|
||||
[[
|
||||
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);
|
||||
|
||||
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])
|
||||
AC_LIBOBJ(kqueue)],
|
||||
[AC_MSG_RESULT(no)],
|
||||
[AC_MSG_RESULT(no)]
|
||||
)
|
||||
fi
|
||||
fi
|
||||
|
||||
haveepollsyscall=no
|
||||
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_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#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 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
|
||||
AC_LIBOBJ(epoll_sub)
|
||||
AC_LIBOBJ(epoll)],
|
||||
[AC_MSG_RESULT(no)],
|
||||
[AC_MSG_RESULT(no)]
|
||||
)
|
||||
fi
|
||||
fi
|
||||
|
||||
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])
|
||||
AC_LIBOBJ(evport)
|
||||
needsignal=yes
|
||||
fi
|
||||
if test "x$bwin32" = "xtrue"; then
|
||||
needsignal=yes
|
||||
fi
|
||||
if test "x$bwin32" = "xtrue"; then
|
||||
needsignal=yes
|
||||
fi
|
||||
if test "x$needsignal" = "xyes" ; then
|
||||
AC_LIBOBJ(signal)
|
||||
fi
|
||||
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_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_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_TYPES([struct in6_addr],[],[],
|
||||
[[#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN6_H
|
||||
#include <netinet/in6.h>
|
||||
#endif]])
|
||||
|
||||
AC_MSG_CHECKING([for socklen_t])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#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_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([],[[const char *cp = __func__;]])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[AC_MSG_RESULT([no])
|
||||
AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([],[[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__])]
|
||||
)]
|
||||
)
|
||||
@@ -26,7 +26,7 @@ AC_DEFUN([MYSQL_PLUGIN],[
|
||||
[__MYSQL_PLUGIN_]AS_TR_CPP([$1])[__],
|
||||
m4_default([$2], [$1 plugin]),
|
||||
m4_default([$3], [plugin for $1]),
|
||||
m4_default([$4], []),
|
||||
m4_default([[$4]], []),
|
||||
)
|
||||
])
|
||||
|
||||
@@ -38,6 +38,7 @@ AC_DEFUN([_MYSQL_PLUGIN],[
|
||||
_MYSQL_PLUGAPPEND([__mysql_plugin_list__],[$1])
|
||||
m4_define([MYSQL_PLUGIN_NAME_]AS_TR_CPP([$1]), [$3])
|
||||
m4_define([MYSQL_PLUGIN_DESC_]AS_TR_CPP([$1]), [$4])
|
||||
m4_ifdef([_AC_ENABLE_IF], [_AC_ENABLE_IF([with],[plugin-$1])])
|
||||
_MYSQL_PLUGAPPEND_META([$1], $5)
|
||||
ifelse(m4_bregexp(__mysql_include__,[/plug\.in$]),-1,[],[
|
||||
MYSQL_PLUGIN_DIRECTORY([$1],
|
||||
@@ -60,7 +61,7 @@ dnl
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([MYSQL_STORAGE_ENGINE],[
|
||||
MYSQL_PLUGIN([$1], [$3], [$4], [[$5]])
|
||||
MYSQL_PLUGIN([$1], [$3], [$4], [$5])
|
||||
MYSQL_PLUGIN_DEFINE([$1], [WITH_]AS_TR_CPP([$1])[_STORAGE_ENGINE])
|
||||
ifelse([$2],[no],[],[
|
||||
_MYSQL_LEGACY_STORAGE_ENGINE(
|
||||
@@ -201,6 +202,30 @@ AC_DEFUN([_MYSQL_PLUGIN_DISABLED],[
|
||||
])
|
||||
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Macro: MYSQL_PLUGIN_WITHOUT
|
||||
dnl
|
||||
dnl SYNOPSIS
|
||||
dnl MYSQL_PLUGIN_WITHOUT([name])
|
||||
dnl
|
||||
dnl DESCRIPTION
|
||||
dnl Exclude the plugin from being built, as if --without-plugin-name
|
||||
dnl was specified.
|
||||
dnl If the plugin was selected manually by --with-plugin-name,
|
||||
dnl excluding it here will abort the configure script with an error,
|
||||
dnl otherwise plugin will be silently disabled.
|
||||
dnl
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
AC_DEFUN([MYSQL_PLUGIN_WITHOUT],[
|
||||
MYSQL_REQUIRE_PLUGIN([$1])
|
||||
if test "X[$with_plugin_]$1" = Xyes; then
|
||||
AC_MSG_ERROR([Plugin $1 cannot be built])
|
||||
else
|
||||
[with_plugin_]$1=no
|
||||
fi
|
||||
])
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Macro: MYSQL_PLUGIN_DEPENDS
|
||||
dnl
|
||||
@@ -267,7 +292,6 @@ dnl we have to recompile these modules when we want to
|
||||
dnl to compile server parts with the different #defines
|
||||
dnl Normally it happens when we compile the embedded server
|
||||
dnl Thus one should mark such files in his handler using this macro
|
||||
dnl (currently only one such a file per plugin is supported)
|
||||
dnl
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
@@ -280,7 +304,7 @@ dnl ---------------------------------------------------------------------------
|
||||
dnl Macro: MYSQL_CONFIGURE_PLUGINS
|
||||
dnl
|
||||
dnl SYNOPSIS
|
||||
dnl MYSQL_PLUGIN_DEPENDS([name,name...])
|
||||
dnl MYSQL_CONFIGURE_PLUGINS([name,name...])
|
||||
dnl
|
||||
dnl DESCRIPTION
|
||||
dnl Used last, emits all required shell code to configure the plugins
|
||||
@@ -343,7 +367,7 @@ AC_DEFUN([_MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
|
||||
AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
m4_ifdef([$5],[
|
||||
AH_TEMPLATE($5, [Include ]$4[ into mysqld])
|
||||
AH_TEMPLATE($5, [Include ]$3[ into mysqld])
|
||||
])
|
||||
AC_MSG_CHECKING([whether to use ]$3)
|
||||
mysql_use_plugin_dir=""
|
||||
@@ -351,10 +375,10 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
if test "X[$mysql_plugin_]$2" = Xyes -a \
|
||||
"X[$with_plugin_]$2" != Xno -o \
|
||||
"X[$with_plugin_]$2" = Xyes; then
|
||||
AC_MSG_RESULT([error])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[error])
|
||||
AC_MSG_ERROR([disabled])
|
||||
fi
|
||||
AC_MSG_RESULT([no])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[no])
|
||||
],[
|
||||
|
||||
# Plugin is not disabled, determine if it should be built,
|
||||
@@ -365,7 +389,7 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
# Plugin directory was removed after autoconf was run; treat
|
||||
# this as a disabled plugin
|
||||
if test "X[$with_plugin_]$2" = Xyes; then
|
||||
AC_MSG_RESULT([error])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[error])
|
||||
AC_MSG_ERROR([disabled])
|
||||
fi
|
||||
|
||||
@@ -376,7 +400,7 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
|
||||
m4_ifdef([$9],[
|
||||
if test "X[$with_plugin_]$2" = Xno; then
|
||||
AC_MSG_RESULT([error])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[error])
|
||||
AC_MSG_ERROR([cannot disable mandatory plugin])
|
||||
fi
|
||||
[mysql_plugin_]$2=yes
|
||||
@@ -391,11 +415,19 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
# Similarly, disable shared plugins when configured with --disable-shared
|
||||
# as libtool will not be able to produce them
|
||||
if test "X[$enable_shared]" = Xno; then
|
||||
if test "X[$mysql_plugin_]$2" != Xyes -a \
|
||||
"X[$with_plugin_]$2" != Xyes; then
|
||||
[with_plugin_]$2=no
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
if test "X[$with_plugin_]$2" = Xno; then
|
||||
AC_MSG_RESULT([no])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[no])
|
||||
else
|
||||
m4_ifdef([$8],m4_ifdef([$7],[],[[with_plugin_]$2='']))
|
||||
if test "X[$mysql_plugin_]$2" != Xyes -a \
|
||||
@@ -408,16 +440,16 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
|
||||
AC_SUBST([plugin_]$2[_shared_target], "$8")
|
||||
AC_SUBST([plugin_]$2[_static_target], [""])
|
||||
[with_plugin_]$2=yes
|
||||
AC_MSG_RESULT([plugin])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[plugin])
|
||||
m4_ifdef([$6],[
|
||||
else
|
||||
[mysql_plugin_]$2=no
|
||||
AC_MSG_RESULT([no])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[no])
|
||||
fi
|
||||
])
|
||||
],[
|
||||
[with_plugin_]$2=no
|
||||
AC_MSG_RESULT([no])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[no])
|
||||
])
|
||||
else
|
||||
m4_ifdef([$7],[
|
||||
@@ -450,7 +482,7 @@ dnl Although this is "pretty", it breaks libmysqld build
|
||||
AC_SUBST([plugin_]$2[_shared_target], [""])
|
||||
],[
|
||||
m4_ifdef([$6],[
|
||||
AC_MSG_RESULT([error])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[error])
|
||||
AC_MSG_ERROR([Plugin $1 does not support static linking])
|
||||
],[
|
||||
m4_ifdef([$5],[
|
||||
@@ -461,17 +493,19 @@ dnl Although this is "pretty", it breaks libmysqld build
|
||||
])
|
||||
])
|
||||
m4_ifdef([$9],[
|
||||
mysql_mandatory_plugins="$mysql_mandatory_plugins [builtin_]$2[_plugin],"
|
||||
mysql_mandatory_plugins="$mysql_mandatory_plugins [builtin_maria_]$2[_plugin],"
|
||||
],[
|
||||
mysql_optional_plugins="$mysql_optional_plugins [builtin_]$2[_plugin],"
|
||||
mysql_optional_plugins="$mysql_optional_plugins [builtin_maria_]$2[_plugin],"
|
||||
])
|
||||
[with_plugin_]$2=yes
|
||||
AC_MSG_RESULT([yes])
|
||||
__MYSQL_EMIT_CHECK_RESULT($3,[yes])
|
||||
m4_ifdef([$11], [
|
||||
condition_dependent_plugin_modules="$condition_dependent_plugin_modules m4_bregexp($11, [[^/]+$], [\&])"
|
||||
condition_dependent_plugin_objects="$condition_dependent_plugin_objects m4_bregexp($11, [[^/]+\.], [\&o])"
|
||||
condition_dependent_plugin_links="$condition_dependent_plugin_links $6/$11"
|
||||
condition_dependent_plugin_includes="$condition_dependent_plugin_includes -I[\$(top_srcdir)]/$6/m4_bregexp($11, [^.+[/$]], [\&])"
|
||||
m4_foreach([plugin], [$11], [
|
||||
condition_dependent_plugin_modules="$condition_dependent_plugin_modules m4_bregexp(plugin, [[^/]+$], [\&])"
|
||||
condition_dependent_plugin_objects="$condition_dependent_plugin_objects m4_bregexp(plugin, [[^/]+\.], [\&o])"
|
||||
condition_dependent_plugin_links="$condition_dependent_plugin_links $6/plugin"
|
||||
condition_dependent_plugin_includes="$condition_dependent_plugin_includes -I[\$(top_srcdir)]/$6/m4_bregexp(plugin, [^.+[/$]], [\&])"
|
||||
])
|
||||
])
|
||||
fi
|
||||
fi
|
||||
@@ -520,6 +554,12 @@ dnl
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([__MYSQL_EMIT_CHECK_RESULT],[
|
||||
AC_MSG_RESULT($2)
|
||||
plugin_report="[$plugin_report]
|
||||
m4_format([ * %-32s $2],$1:)"
|
||||
])
|
||||
|
||||
AC_DEFUN([_MYSQL_EMIT_PLUGIN_ACTIONS],[
|
||||
ifelse($#, 0, [], $#, 1, [
|
||||
_MYSQL_EMIT_PLUGIN_ACTION([$1])
|
||||
@@ -788,7 +828,7 @@ AC_DEFUN([_MYSQL_CHECK_PLUGIN_ARGS],[
|
||||
AC_DEFUN([__MYSQL_CHECK_PLUGIN_ARGS],[
|
||||
AC_ARG_WITH([plugins],
|
||||
AS_HELP_STRING([--with-plugins=PLUGIN[[[[[,PLUGIN..]]]]]],
|
||||
[Plugins to include in mysqld. (default is: $1) Must be a
|
||||
[Plugins to include in mysqld. Must be a
|
||||
configuration name or a comma separated list of plugins.])
|
||||
AS_HELP_STRING([],
|
||||
[Available configurations are:] dnl
|
||||
|
||||
179
configure.in
179
configure.in
@@ -27,7 +27,12 @@ dnl
|
||||
dnl When changing the major version number please also check the switch
|
||||
dnl statement in mysqlbinlog::check_master_version(). You may also need
|
||||
dnl to update version.c in ndb.
|
||||
AC_INIT([MySQL Server], [5.5.7-rc], [], [mysql])
|
||||
dnl
|
||||
dnl When merging new MySQL releases, update the version number to match the
|
||||
dnl MySQL version number.
|
||||
dnl
|
||||
dnl Note: the following line must be parseable by win/configure.js:GetVersion()
|
||||
AC_INIT([MariaDB Server], [5.5.7-MariaDB-alpha], [], [mysql])
|
||||
|
||||
AC_CONFIG_SRCDIR([sql/mysqld.cc])
|
||||
AC_CANONICAL_SYSTEM
|
||||
@@ -92,6 +97,7 @@ sinclude(config/ac-macros/large_file.m4)
|
||||
sinclude(config/ac-macros/misc.m4)
|
||||
sinclude(config/ac-macros/readline.m4)
|
||||
sinclude(config/ac-macros/ssl.m4)
|
||||
sinclude(config/ac-macros/libevent.m4)
|
||||
sinclude(config/ac-macros/zlib.m4)
|
||||
|
||||
# Remember to add a directory sql/share/LANGUAGE
|
||||
@@ -250,14 +256,6 @@ then
|
||||
GXX="no"
|
||||
fi
|
||||
|
||||
if test "$ac_cv_prog_gcc" = "yes"
|
||||
then
|
||||
AS="$CC -c"
|
||||
AC_SUBST(AS)
|
||||
else
|
||||
AC_PATH_PROG(AS, as, as)
|
||||
fi
|
||||
|
||||
# Still need ranlib for readline; local static use only so no libtool.
|
||||
AC_PROG_RANLIB
|
||||
# We use libtool
|
||||
@@ -284,8 +282,40 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
|
||||
|
||||
# Not critical since the generated file is distributed
|
||||
AC_CHECK_PROGS(YACC, ['bison -y -p MYSQL'])
|
||||
AC_CHECK_PROG(PDFMANUAL, pdftex, manual.pdf)
|
||||
AC_CHECK_PROG(DVIS, tex, manual.dvi)
|
||||
|
||||
#check the return type of sprintf
|
||||
AC_MSG_CHECKING("return type of sprintf")
|
||||
AC_TRY_RUN([
|
||||
int main()
|
||||
{
|
||||
char* s = "hello";
|
||||
char buf[6];
|
||||
if((int)sprintf(buf, s) == strlen(s))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
],
|
||||
[AC_DEFINE(SPRINTF_RETURNS_INT, [1], [POSIX sprintf])
|
||||
AC_MSG_RESULT("int")],
|
||||
[AC_TRY_RUN([
|
||||
int main()
|
||||
{
|
||||
char* s = "hello";
|
||||
char buf[6];
|
||||
if((char*)sprintf(buf,s) == buf + strlen(s))
|
||||
return 0;
|
||||
return -1;
|
||||
} ],
|
||||
[AC_DEFINE(SPRINTF_RETURNS_PTR, [1], [Broken sprintf])
|
||||
AC_MSG_RESULT("ptr")],
|
||||
[AC_DEFINE(SPRINTF_RETURNS_GARBAGE, [1], [Broken sprintf])
|
||||
AC_MSG_RESULT("garbage")]
|
||||
)],
|
||||
# Cross compile, assume POSIX
|
||||
[AC_DEFINE(SPRINTF_RETURNS_INT, [1], [POSIX sprintf])
|
||||
AC_MSG_RESULT("int (we assume)")]
|
||||
)
|
||||
|
||||
AC_PATH_PROG(uname_prog, uname, no)
|
||||
|
||||
@@ -379,7 +409,7 @@ export CC CXX CFLAGS LD LDFLAGS AR ARFLAGS
|
||||
if test "$GCC" = "yes"
|
||||
then
|
||||
# mysqld requires -fno-implicit-templates.
|
||||
# Disable exceptions as they seams to create problems with gcc and threads.
|
||||
# Disable exceptions as they seem to create problems with gcc and threads.
|
||||
# mysqld doesn't use run-time-type-checking, so we disable it.
|
||||
# We should use -Wno-invalid-offsetof flag to disable some warnings from gcc
|
||||
# regarding offset() usage in C++ which are done in a safe manner in the
|
||||
@@ -612,7 +642,7 @@ AC_CHECK_TOOL([NM], [nm])
|
||||
|
||||
if test "$TARGET_LINUX" = "true" -a "$static_nss" = ""
|
||||
then
|
||||
tmp=`$NM ${other_libc_lib:-/usr/lib*}/libc.a | grep _nss_files_getaliasent_r1`
|
||||
tmp=`$NM ${other_libc_lib:-/usr/lib*}/libc.a 2>&1 | grep _nss_files_getaliasent_r1`
|
||||
if test -n "$tmp"
|
||||
then
|
||||
STATIC_NSS_FLAGS="-lc -lnss_files -lnss_dns -lresolv"
|
||||
@@ -671,8 +701,7 @@ AC_ARG_ENABLE(assembler,
|
||||
|
||||
AC_MSG_CHECKING(if we should use assembler functions)
|
||||
# For now we only support assembler on i386 and sparc systems
|
||||
AM_CONDITIONAL(ASSEMBLER_x86, test "$ENABLE_ASSEMBLER" = "yes" -a "$BASE_MACHINE_TYPE" = "i386" && $AS strings/strings-x86.s -o checkassembler >/dev/null 2>&1 && test -f checkassembler && (rm -f checkassembler; exit 0;))
|
||||
AM_CONDITIONAL(ASSEMBLER_sparc64, test "$ENABLE_ASSEMBLER" = "yes" -a "$BASE_MACHINE_TYPE" = "sparcv9")
|
||||
AM_CONDITIONAL(ASSEMBLER_x86, test "$ENABLE_ASSEMBLER" = "yes" -a "$BASE_MACHINE_TYPE" = "i386" && $CCAS $CCASFLAGS -c strings/strings-x86.s -o checkassembler >/dev/null 2>&1 && test -f checkassembler && (rm -f checkassembler; exit 0;))
|
||||
AM_CONDITIONAL(ASSEMBLER, test "$ASSEMBLER_x86_TRUE" = "")
|
||||
|
||||
if test "$ASSEMBLER_TRUE" = ""
|
||||
@@ -798,13 +827,13 @@ AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(fcntl.h fenv.h float.h floatingpoint.h fpu_control.h \
|
||||
ieeefp.h limits.h memory.h pwd.h select.h poll.h \
|
||||
stdlib.h stddef.h \
|
||||
ieeefp.h limits.h memory.h pwd.h select.h poll.h fnmatch.h \
|
||||
stdlib.h stddef.h sys/stat.h \
|
||||
strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \
|
||||
sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
|
||||
unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \
|
||||
sys/ioctl.h malloc.h sys/malloc.h sys/ipc.h sys/shm.h linux/config.h \
|
||||
sys/prctl.h sys/resource.h sys/param.h port.h ieeefp.h \
|
||||
sys/prctl.h sys/resource.h sys/param.h port.h ieeefp.h linux/unistd.h \
|
||||
execinfo.h)
|
||||
|
||||
AC_CHECK_HEADERS([xfs/xfs.h])
|
||||
@@ -815,6 +844,7 @@ AC_CHECK_HEADERS([xfs/xfs.h])
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
AC_CHECK_LIB(m, floor, [], AC_CHECK_LIB(m, __infinity))
|
||||
AC_CHECK_FUNCS(log2)
|
||||
|
||||
AC_CHECK_LIB(nsl_r, gethostbyname_r, [],
|
||||
AC_CHECK_LIB(nsl, gethostbyname_r))
|
||||
@@ -1657,9 +1687,8 @@ case "$with_mysqld_ldflags " in
|
||||
;;
|
||||
|
||||
*)
|
||||
# Check for dlopen, needed for user definable functions
|
||||
# Check for dlopen, needed for user definable functions and plugins
|
||||
# This must be checked after threads on AIX
|
||||
# We only need this for mysqld, not for the clients.
|
||||
|
||||
my_save_LIBS="$LIBS"
|
||||
LIBS=""
|
||||
@@ -1738,8 +1767,9 @@ AC_ARG_WITH(debug,
|
||||
if test "$with_debug" = "yes"
|
||||
then
|
||||
AC_DEFINE([DBUG_ON], [1], [Use libdbug])
|
||||
CFLAGS="$DEBUG_CFLAGS $DEBUG_OPTIMIZE_CC -DSAFE_MUTEX $CFLAGS"
|
||||
CXXFLAGS="$DEBUG_CXXFLAGS $DEBUG_OPTIMIZE_CXX -DSAFE_MUTEX $CXXFLAGS"
|
||||
AC_DEFINE([SAFE_MUTEX], [1], [Use safe mutexes])
|
||||
CFLAGS="$DEBUG_CFLAGS $DEBUG_OPTIMIZE_CC $CFLAGS"
|
||||
CXXFLAGS="$DEBUG_CXXFLAGS $DEBUG_OPTIMIZE_CXX $CXXFLAGS"
|
||||
else
|
||||
# Optimized version. No debug
|
||||
AC_DEFINE([DBUG_OFF], [1], [Don't use libdbug])
|
||||
@@ -1791,23 +1821,6 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([atomic-ops],
|
||||
AS_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
|
||||
[Implement atomic operations using pthread rwlocks or atomic CPU
|
||||
instructions for multi-processor or uniprocessor
|
||||
configuration. By default gcc built-in sync functions are used,
|
||||
if available and 'smp' configuration otherwise.]))
|
||||
case "$with_atomic_ops" in
|
||||
"up") AC_DEFINE([MY_ATOMIC_MODE_DUMMY], [1],
|
||||
[Assume single-CPU mode, no concurrency]) ;;
|
||||
"rwlocks") AC_DEFINE([MY_ATOMIC_MODE_RWLOCKS], [1],
|
||||
[Use pthread rwlocks for atomic ops]) ;;
|
||||
"smp") ;;
|
||||
"")
|
||||
;;
|
||||
*) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;
|
||||
esac
|
||||
|
||||
AC_CACHE_CHECK([whether the compiler provides atomic builtins],
|
||||
[mysql_cv_gcc_atomic_builtins],
|
||||
[AC_RUN_IFELSE(
|
||||
@@ -1883,6 +1896,26 @@ if test "x$mysql_cv_solaris_atomic" = xyes; then
|
||||
AC_DEFINE(HAVE_SOLARIS_ATOMIC, 1,
|
||||
[Define to 1 if OS provides atomic_* functions like Solaris.])
|
||||
fi
|
||||
AC_ARG_WITH([atomic-ops],
|
||||
AC_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
|
||||
[Implement atomic operations using pthread rwlocks or atomic CPU
|
||||
instructions for multi-processor or uniprocessor
|
||||
configuration. By default gcc built-in sync functions are used,
|
||||
if available and 'smp' configuration otherwise.]))
|
||||
case "$with_atomic_ops" in
|
||||
"up") AC_DEFINE([MY_ATOMIC_MODE_DUMMY], [1],
|
||||
[Assume single-CPU mode, no concurrency]) ;;
|
||||
"rwlocks") AC_DEFINE([MY_ATOMIC_MODE_RWLOCKS], [1],
|
||||
[Use pthread rwlocks for atomic ops]) ;;
|
||||
"smp") ;;
|
||||
"")
|
||||
if test "x$mysql_cv_gcc_atomic_builtins" = xyes_but_disabled; then
|
||||
AC_DEFINE([MY_ATOMIC_MODE_GCC_BUILTINS], [1],
|
||||
[Use GCC atomic builtins for atomic ops])
|
||||
fi
|
||||
;;
|
||||
*) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;
|
||||
esac
|
||||
|
||||
# Force static compilation to avoid linking problems/get more speed
|
||||
AC_ARG_WITH(mysqld-ldflags,
|
||||
@@ -2159,7 +2192,7 @@ MYSQL_TYPE_QSORT
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_VPRINTF
|
||||
|
||||
AC_CHECK_FUNCS(alarm bfill bmove bsearch bzero \
|
||||
AC_CHECK_FUNCS(alarm bcmp bfill bmove bsearch bzero \
|
||||
chsize cuserid fchmod fcntl \
|
||||
fdatasync fesetround finite fpresetsticky fpsetmask fsync ftruncate \
|
||||
getcwd gethostbyaddr_r gethostbyname_r getpass getpassphrase getpwnam \
|
||||
@@ -2187,7 +2220,18 @@ case "$target" in
|
||||
# We also disable for SCO for the time being, the headers for the
|
||||
# thread library we use conflicts with other headers.
|
||||
;;
|
||||
*) AC_CHECK_FUNCS(clock_gettime)
|
||||
*)
|
||||
# most systems require the program be linked with librt library to use
|
||||
# the function clock_gettime
|
||||
my_save_LIBS="$LIBS"
|
||||
LIBS=""
|
||||
AC_CHECK_LIB(rt,clock_gettime)
|
||||
LIBRT=$LIBS
|
||||
LIBS="$my_save_LIBS"
|
||||
AC_SUBST(LIBRT)
|
||||
|
||||
LIBS="$LIBS $LIBRT"
|
||||
AC_CHECK_FUNCS(clock_gettime)
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -2594,6 +2638,7 @@ MYSQL_CHECK_BIG_TABLES
|
||||
MYSQL_CHECK_MAX_INDEXES
|
||||
MYSQL_CHECK_VIO
|
||||
MYSQL_CHECK_SSL
|
||||
MYSQL_CHECK_LIBEVENT
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Declare our plugin modules
|
||||
@@ -2601,6 +2646,17 @@ MYSQL_CHECK_SSL
|
||||
# functions tested above
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
# MyISAM is declared here,not in storage/myisam/plug.in
|
||||
# because we want it to be the first in the list of plugins,
|
||||
# Maria needs it. When it'll be fixed the declaration below can
|
||||
# be removed and restored (uncommented) in storage/myisam/plug.in
|
||||
MYSQL_STORAGE_ENGINE(myisam,no, [MyISAM Storage Engine],
|
||||
[Traditional non-transactional MySQL tables])
|
||||
MYSQL_PLUGIN_DIRECTORY(myisam, [storage/myisam])
|
||||
MYSQL_PLUGIN_STATIC(myisam, [libmyisam.a])
|
||||
MYSQL_PLUGIN_MANDATORY(myisam) dnl Default
|
||||
MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(myisam, [ha_myisam.cc])
|
||||
|
||||
MYSQL_STORAGE_ENGINE(partition, partition, [Partition Support],
|
||||
[MySQL Partitioning Support], [max,max-no-ndb])
|
||||
|
||||
@@ -2808,8 +2864,6 @@ AC_SUBST(readline_basedir)
|
||||
AC_SUBST(readline_link)
|
||||
AC_SUBST(readline_h_ln_cmd)
|
||||
|
||||
|
||||
|
||||
# Include man pages, if desired, adapted to the configured parts.
|
||||
if test X"$with_man" = Xyes
|
||||
then
|
||||
@@ -2871,7 +2925,7 @@ server_scripts=
|
||||
|
||||
dnl This probably should be cleaned up more - for now the threaded
|
||||
dnl client is just using plain-old libs.
|
||||
sql_client_dirs="strings mysys dbug extra regex libmysql"
|
||||
sql_client_dirs="strings mysys dbug extra regex libmysql unittest"
|
||||
|
||||
AM_CONDITIONAL(THREAD_SAFE_CLIENT, test "$THREAD_SAFE_CLIENT" != "no")
|
||||
|
||||
@@ -2882,7 +2936,7 @@ then
|
||||
fi
|
||||
sql_client_dirs="$sql_client_dirs client"
|
||||
|
||||
CLIENT_LIBS="$NON_THREADED_LIBS $openssl_libs $ZLIB_LIBS $STATIC_NSS_FLAGS"
|
||||
CLIENT_LIBS="$NON_THREADED_LIBS $openssl_libs $ZLIB_LIBS $STATIC_NSS_FLAGS $LIBRT"
|
||||
|
||||
AC_SUBST(CLIENT_LIBS)
|
||||
AC_SUBST(CLIENT_THREAD_LIBS)
|
||||
@@ -2895,7 +2949,7 @@ then
|
||||
AC_DEFINE([THREAD], [1],
|
||||
[Define if you want to have threaded code. This may be undef on client code])
|
||||
# Avoid _PROGRAMS names
|
||||
THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o"
|
||||
THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o mf_keycaches.o waiting_threads.o"
|
||||
AC_SUBST(THREAD_LOBJECTS)
|
||||
fi
|
||||
AM_CONDITIONAL(NEED_THREAD, test "$with_server" != "no" -o "$THREAD_SAFE_CLIENT" != "no")
|
||||
@@ -2907,6 +2961,7 @@ then
|
||||
|
||||
sql_server="vio sql"
|
||||
fi
|
||||
AM_CONDITIONAL(THREAD, test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no")
|
||||
|
||||
# "innochecksum" is not in the "innobase/" subdirectory, but should be switched
|
||||
AM_CONDITIONAL([BUILD_INNODB_TOOLS], [test X"$with_plugin_innobase" = Xyes])
|
||||
@@ -3031,18 +3086,36 @@ AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl
|
||||
)
|
||||
|
||||
AC_CONFIG_COMMANDS([default], , test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h)
|
||||
AC_CONFIG_COMMANDS([my_config.h], cp include/config.h include/my_config.h)
|
||||
|
||||
# Ensure that table handlers gets all modifications to CFLAGS/CXXFLAGS
|
||||
AC_CONFIG_COMMANDS_POST(ac_configure_args="$ac_configure_args CFLAGS='$CFLAGS' CXXFLAGS='$CXXFLAGS'")
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo "---"
|
||||
echo "Configuration summary for $PACKAGE_NAME version $VERSION"
|
||||
echo "$plugin_report" | sort
|
||||
echo ""
|
||||
echo " * Installation prefix: $prefix"
|
||||
echo " * System type: $SYSTEM_TYPE"
|
||||
echo " * Host CPU: $host_cpu"
|
||||
echo " * C Compiler: $CC_VERSION"
|
||||
echo " * C++ Compiler: $CXX_VERSION"
|
||||
echo " * Debug enabled: $with_debug"
|
||||
echo " * Community Features: $ENABLE_COMMUNITY_FEATURES"
|
||||
echo ""
|
||||
echo "---"
|
||||
echo ""
|
||||
echo "You can find information about MariaDB at"
|
||||
echo "http://kb.askmonty.org/"
|
||||
echo ""
|
||||
echo "Remember to check the platform specific part of the reference manual for"
|
||||
echo "hints about installing MariaDB on your platform. Also have a look at the"
|
||||
echo "files in the Docs directory."
|
||||
|
||||
# The first line "Thank you ..." is checked in ./Do-compile to verify that configure
|
||||
# ended sucessfully - don't remove it.
|
||||
echo
|
||||
echo "Thank you for choosing MySQL!"
|
||||
echo
|
||||
echo "Remember to check the platform specific part of the reference manual"
|
||||
echo "for hints about installing MySQL on your platform."
|
||||
echo "Also have a look at the files in the Docs directory."
|
||||
echo
|
||||
echo ""
|
||||
echo "Thank you for choosing MariaDB!"
|
||||
echo ""
|
||||
|
||||
@@ -65,4 +65,3 @@ output5.r: factorial
|
||||
# a hack to have executable in builddir, not in srcdir
|
||||
tests-t: tests-t.pl
|
||||
cp -f $(srcdir)/tests-t.pl ./tests-t
|
||||
|
||||
|
||||
61
dbug/dbug.c
61
dbug/dbug.c
@@ -86,6 +86,7 @@
|
||||
|
||||
#undef SAFE_MUTEX
|
||||
#include <my_global.h>
|
||||
#undef SAFE_MUTEX
|
||||
#include <m_string.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -279,7 +280,7 @@ typedef struct _db_code_state_ {
|
||||
#define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
|
||||
static struct link *ListAddDel(struct link *, const char *, const char *, int);
|
||||
static struct link *ListCopy(struct link *);
|
||||
static int InList(struct link *linkp,const char *cp);
|
||||
static int InList(struct link *linkp,const char *cp, int exact_match);
|
||||
static uint ListFlags(struct link *linkp);
|
||||
static void FreeList(struct link *linkp);
|
||||
|
||||
@@ -373,7 +374,7 @@ static CODE_STATE *code_state(void)
|
||||
if (!init_done)
|
||||
{
|
||||
init_done=TRUE;
|
||||
pthread_mutex_init(&THR_LOCK_dbug, NULL);
|
||||
pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
|
||||
bzero(&init_settings, sizeof(init_settings));
|
||||
init_settings.out_file=stderr;
|
||||
init_settings.flags=OPEN_APPEND;
|
||||
@@ -487,12 +488,18 @@ int DbugParse(CODE_STATE *cs, const char *control)
|
||||
const char *end;
|
||||
int rel, f_used=0;
|
||||
struct settings *stack;
|
||||
int org_cs_locked;
|
||||
|
||||
stack= cs->stack;
|
||||
|
||||
if (!(org_cs_locked= cs->locked))
|
||||
{
|
||||
cs->locked= 1;
|
||||
pthread_mutex_lock(&THR_LOCK_dbug);
|
||||
}
|
||||
|
||||
if (control[0] == '-' && control[1] == '#')
|
||||
control+=2;
|
||||
|
||||
rel= control[0] == '+' || control[0] == '-';
|
||||
if ((!rel || (!stack->out_file && !stack->next)))
|
||||
{
|
||||
@@ -540,7 +547,8 @@ int DbugParse(CODE_STATE *cs, const char *control)
|
||||
int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
|
||||
if (sign) control++;
|
||||
c= *control++;
|
||||
if (*control == ',') control++;
|
||||
if (*control == ',')
|
||||
control++;
|
||||
/* XXX when adding new cases here, don't forget _db_explain_ ! */
|
||||
switch (c) {
|
||||
case 'd':
|
||||
@@ -700,6 +708,11 @@ int DbugParse(CODE_STATE *cs, const char *control)
|
||||
control=end+1;
|
||||
end= DbugStrTok(control);
|
||||
}
|
||||
if (!org_cs_locked)
|
||||
{
|
||||
pthread_mutex_unlock(&THR_LOCK_dbug);
|
||||
cs->locked= 0;
|
||||
}
|
||||
return !rel || f_used;
|
||||
}
|
||||
|
||||
@@ -851,7 +864,7 @@ void _db_set_(const char *control)
|
||||
*
|
||||
* Given pointer to a debug control string in "control", pushes
|
||||
* the current debug settings, parses the control string, and sets
|
||||
* up a new debug settings with DbugParse()
|
||||
* up a new debug settings
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -866,7 +879,6 @@ void _db_push_(const char *control)
|
||||
FixTraceFlags(old_fflags, cs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns TRUE if session-local settings have been set.
|
||||
*/
|
||||
@@ -954,7 +966,7 @@ void _db_pop_()
|
||||
} while (0)
|
||||
#define str_to_buf(S) do { \
|
||||
char_to_buf(','); \
|
||||
buf=strnmov(buf, (S), len+1); \
|
||||
buf=strnmov(buf, (S), (uint) (end-buf)); \
|
||||
if (buf >= end) goto overflow; \
|
||||
} while (0)
|
||||
#define list_to_buf(l, f) do { \
|
||||
@@ -1221,6 +1233,7 @@ void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
|
||||
my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
|
||||
DbugExit(buf);
|
||||
}
|
||||
|
||||
#ifndef THREAD
|
||||
if (DoProfile(cs))
|
||||
(void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
|
||||
@@ -1313,11 +1326,11 @@ void _db_doprnt_(const char *format,...)
|
||||
|
||||
va_start(args,format);
|
||||
|
||||
if (!cs->locked)
|
||||
pthread_mutex_lock(&THR_LOCK_dbug);
|
||||
if (_db_keyword_(cs, cs->u_keyword, 0))
|
||||
{
|
||||
int save_errno=errno;
|
||||
if (!cs->locked)
|
||||
pthread_mutex_lock(&THR_LOCK_dbug);
|
||||
DoPrefix(cs, cs->u_line);
|
||||
if (TRACING)
|
||||
Indent(cs, cs->level + 1);
|
||||
@@ -1328,6 +1341,9 @@ void _db_doprnt_(const char *format,...)
|
||||
DbugFlush(cs);
|
||||
errno=save_errno;
|
||||
}
|
||||
else if (!cs->locked)
|
||||
pthread_mutex_unlock(&THR_LOCK_dbug);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -1369,10 +1385,10 @@ void _db_dump_(uint _line_, const char *keyword,
|
||||
CODE_STATE *cs;
|
||||
get_code_state_or_return;
|
||||
|
||||
if (_db_keyword_(cs, keyword, 0))
|
||||
{
|
||||
if (!cs->locked)
|
||||
pthread_mutex_lock(&THR_LOCK_dbug);
|
||||
if (_db_keyword_(cs, keyword, 0))
|
||||
{
|
||||
DoPrefix(cs, _line_);
|
||||
if (TRACING)
|
||||
{
|
||||
@@ -1402,6 +1418,8 @@ void _db_dump_(uint _line_, const char *keyword,
|
||||
(void) fputc('\n',cs->stack->out_file);
|
||||
DbugFlush(cs);
|
||||
}
|
||||
else if (!cs->locked)
|
||||
pthread_mutex_unlock(&THR_LOCK_dbug);
|
||||
}
|
||||
|
||||
|
||||
@@ -1546,13 +1564,13 @@ static struct link *ListCopy(struct link *orig)
|
||||
*
|
||||
*/
|
||||
|
||||
static int InList(struct link *linkp, const char *cp)
|
||||
static int InList(struct link *linkp, const char *cp, int exact_match)
|
||||
{
|
||||
int result;
|
||||
|
||||
for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
|
||||
{
|
||||
if (!fnmatch(linkp->str, cp, 0))
|
||||
if (!(exact_match ? strcmp(linkp->str,cp) : fnmatch(linkp->str, cp, 0)))
|
||||
return linkp->flags;
|
||||
if (!(linkp->flags & EXCLUDE))
|
||||
result=NOT_MATCHED;
|
||||
@@ -1721,8 +1739,8 @@ void _db_end_()
|
||||
static int DoTrace(CODE_STATE *cs)
|
||||
{
|
||||
if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
|
||||
InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
|
||||
switch(InList(cs->stack->functions, cs->func)) {
|
||||
InList(cs->stack->processes, cs->process, 0) & (MATCHED|INCLUDE))
|
||||
switch(InList(cs->stack->functions, cs->func, 0)) {
|
||||
case INCLUDE|SUBDIR: return ENABLE_TRACE;
|
||||
case INCLUDE: return DO_TRACE;
|
||||
case MATCHED|SUBDIR:
|
||||
@@ -1759,10 +1777,10 @@ static int DoTrace(CODE_STATE *cs)
|
||||
#ifndef THREAD
|
||||
static BOOLEAN DoProfile(CODE_STATE *cs)
|
||||
{
|
||||
return PROFILING &&
|
||||
return (PROFILING &&
|
||||
cs->level <= cs->stack->maxdepth &&
|
||||
InList(cs->stack->p_functions, cs->func) & (INCLUDE|MATCHED) &&
|
||||
InList(cs->stack->processes, cs->process) & (INCLUDE|MATCHED);
|
||||
InList(cs->stack->p_functions, cs->func, 0) & (INCLUDE|MATCHED) &&
|
||||
InList(cs->stack->processes, cs->process, 0) & (INCLUDE|MATCHED));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1795,11 +1813,11 @@ FILE *_db_fp_(void)
|
||||
|
||||
BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
|
||||
{
|
||||
int match= strict ? INCLUDE : INCLUDE|MATCHED;
|
||||
get_code_state_if_not_set_or_return FALSE;
|
||||
strict=strict ? INCLUDE : INCLUDE|MATCHED;
|
||||
|
||||
return DEBUGGING && DoTrace(cs) & DO_TRACE &&
|
||||
InList(cs->stack->keywords, keyword) & strict;
|
||||
return (DEBUGGING && DoTrace(cs) & DO_TRACE &&
|
||||
InList(cs->stack->keywords, keyword, strict) & match);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2084,6 +2102,7 @@ static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
|
||||
{
|
||||
if (fp && fp != stderr && fp != stdout && fclose(fp) == EOF)
|
||||
{
|
||||
if (!cs->locked)
|
||||
pthread_mutex_lock(&THR_LOCK_dbug);
|
||||
(void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
|
||||
perror("");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
|
||||
die <<EEE unless @ARGV;
|
||||
Usage: $0 func1 [func2 [ ...] ]
|
||||
|
||||
@@ -11,16 +10,16 @@ DBUG_ENTER() and DBUG_POP(); right before DBUG_RETURN in every such a function.
|
||||
EEE
|
||||
|
||||
$re=join('|', @ARGV);
|
||||
$skip='';
|
||||
|
||||
while(<STDIN>) {
|
||||
print unless $skip;
|
||||
($thd) = /^(T@\d+)/;
|
||||
print unless $skip{$thd};
|
||||
next unless /^(?:.*: )*((?:\| )*)([<>])($re)\n/o;
|
||||
if ($2 eq '>') {
|
||||
$skip=$1.$3 unless $skip;
|
||||
$skip{$thd}=$1.$3 unless $skip{$thd};
|
||||
next;
|
||||
}
|
||||
next if $skip ne $1.$3;
|
||||
$skip='';
|
||||
next if $skip{$thd} ne $1.$3;
|
||||
delete $skip{$thd};
|
||||
print;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
|
||||
TARGET_LINK_LIBRARIES(resolveip ${SOLARIS_NSL})
|
||||
ENDIF()
|
||||
|
||||
|
||||
MYSQL_ADD_EXECUTABLE(replace replace.c)
|
||||
TARGET_LINK_LIBRARIES(replace mysys)
|
||||
IF(UNIX)
|
||||
@@ -79,3 +78,5 @@ IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(mysql_waitpid mysys)
|
||||
ENDIF()
|
||||
|
||||
MESSAGE("TODO: Support libevent")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2000-2006 MySQL AB
|
||||
# Copyright (C) 2000-2006 MySQL AB, 2009 Monty Program AB
|
||||
#
|
||||
# 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
|
||||
@@ -22,9 +22,10 @@ BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \
|
||||
$(top_builddir)/include/sql_state.h \
|
||||
$(top_builddir)/include/mysqld_ername.h
|
||||
pkginclude_HEADERS= $(BUILT_SOURCES)
|
||||
DISTCLEANFILES = $(BUILT_SOURCES)
|
||||
SUBDIRS = @yassl_dir@
|
||||
DIST_SUBDIRS = yassl
|
||||
EXTRA_PROGRAMS = comp_err
|
||||
DISTCLEANFILES = $(BUILT_SOURCES) $(EXTRA_PROGRAMS)
|
||||
SUBDIRS = @yassl_dir@ @libevent_dir@
|
||||
DIST_SUBDIRS = yassl libevent
|
||||
|
||||
# This will build mysqld_error.h, mysqld_ername.h and sql_state.h
|
||||
# NOTE Built files should depend on their sources to avoid
|
||||
@@ -50,7 +51,6 @@ bin_PROGRAMS += innochecksum
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = charset2html
|
||||
EXTRA_PROGRAMS = comp_err
|
||||
EXTRA_DIST = CMakeLists.txt
|
||||
|
||||
perror.o: perror.c
|
||||
|
||||
@@ -108,7 +108,8 @@ static struct my_option my_long_options[]=
|
||||
NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"version", 'V', "Prints version", 0, 0, 0, GET_NO_ARG,
|
||||
NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"charset", 'C', "Charset dir", &charsets_dir, &charsets_dir,
|
||||
{"charset", 'C', "Charset dir",
|
||||
(char**) &charsets_dir, (char**) &charsets_dir,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"in_file", 'F', "Input file", &TXTFILE, &TXTFILE,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
|
||||
35
extra/libevent/CMakeLists.txt
Normal file
35
extra/libevent/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/extra/libevent
|
||||
${CMAKE_SOURCE_DIR}/extra/libevent/compat
|
||||
${CMAKE_SOURCE_DIR}/extra/libevent/WIN32-Code
|
||||
${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
IF(MSVC)
|
||||
ADD_DEFINITIONS("-DWIN32 -DHAVE_CONFIG_H")
|
||||
ENDIF(MSVC)
|
||||
|
||||
SET(LIBEVENT_SOURCES
|
||||
buffer.c
|
||||
evbuffer.c
|
||||
event.c
|
||||
evutil.c
|
||||
log.c
|
||||
signal.c
|
||||
strlcpy.c
|
||||
WIN32-Code/win32.c
|
||||
WIN32-Code/config.h
|
||||
WIN32-Code/misc.c
|
||||
WIN32-Code/misc.h
|
||||
event-internal.h
|
||||
event.h
|
||||
evsignal.h
|
||||
evutil.h
|
||||
log.h
|
||||
min_heap.h
|
||||
strlcpy-internal.h
|
||||
)
|
||||
|
||||
CONFIGURE_FILE(WIN32-Code/config.h ${CMAKE_SOURCE_DIR}/extra/libevent/event-config.h COPYONLY)
|
||||
IF(NOT SOURCE_SUBLIBS)
|
||||
ADD_LIBRARY(libevent ${LIBEVENT_SOURCES})
|
||||
ENDIF(NOT SOURCE_SUBLIBS)
|
||||
39
extra/libevent/Makefile.am
Normal file
39
extra/libevent/Makefile.am
Normal file
@@ -0,0 +1,39 @@
|
||||
AUTOMAKE_OPTIONS = foreign no-dependencies
|
||||
|
||||
EXTRA_DIST = README compat/sys \
|
||||
buffer.c epoll.c evbuffer.c event.c evport.c evutil.c kqueue.c poll.c \
|
||||
signal.c devpoll.c epoll_sub.c evdns.c event_tagging.c evrpc.c http.c \
|
||||
log.c select.c strlcpy.c \
|
||||
evdns.h event.h evrpc-internal.h evsignal.h http-internal.h log.h \
|
||||
min_heap.h event-internal.h evhttp.h evrpc.h evutil.h strlcpy-internal.h \
|
||||
WIN32-Code/misc.c WIN32-Code/misc.h WIN32-Code/config.h WIN32-Code/tree.h \
|
||||
WIN32-Code/win32.c CMakeLists.txt
|
||||
|
||||
|
||||
DISTCLEANFILES = event-config.h
|
||||
|
||||
noinst_LIBRARIES = libevent.a
|
||||
|
||||
libevent_a_SOURCES = event.c buffer.c evbuffer.c log.c evutil.c \
|
||||
select.c poll.c epoll.c epoll_sub.c devpoll.c kqueue.c \
|
||||
evport.c signal.c
|
||||
|
||||
include_HEADERS = event.h evutil.h event-config.h
|
||||
|
||||
BUILT_SOURCES = event-config.h
|
||||
|
||||
event-config.h: $(top_builddir)/include/config.h
|
||||
echo '/* event-config.h' > $@
|
||||
echo ' * Generated by autoconf; post-processed by libevent.' >> $@
|
||||
echo ' * Do not edit this file.' >> $@
|
||||
echo ' * Do not rely on macros in this file existing in later versions.'>> $@
|
||||
echo ' */' >> $@
|
||||
echo '#ifndef _EVENT_CONFIG_H_' >> $@
|
||||
echo '#define _EVENT_CONFIG_H_' >> $@
|
||||
|
||||
sed -e 's/#define /#define _EVENT_/' \
|
||||
-e 's/#undef /#undef _EVENT_/' \
|
||||
-e 's/#ifndef /#ifndef _EVENT_/' < $(top_builddir)/include/config.h >> $@
|
||||
echo "#endif" >> $@
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir)/compat -I$(top_srcdir)/include
|
||||
57
extra/libevent/README
Normal file
57
extra/libevent/README
Normal file
@@ -0,0 +1,57 @@
|
||||
To build libevent, type
|
||||
|
||||
$ ./configure && make
|
||||
|
||||
(If you got libevent from the subversion repository, you will
|
||||
first need to run the included "autogen.sh" script in order to
|
||||
generate the configure script.)
|
||||
|
||||
Install as root via
|
||||
|
||||
# make install
|
||||
|
||||
You can run the regression tests by
|
||||
|
||||
$ make verify
|
||||
|
||||
Before, reporting any problems, please run the regression tests.
|
||||
|
||||
To enable the low-level tracing build the library as:
|
||||
|
||||
CFLAGS=-DUSE_DEBUG ./configure [...]
|
||||
|
||||
Acknowledgements:
|
||||
-----------------
|
||||
|
||||
The following people have helped with suggestions, ideas, code or
|
||||
fixing bugs:
|
||||
|
||||
Alejo
|
||||
Weston Andros Adamson
|
||||
William Ahern
|
||||
Stas Bekman
|
||||
Andrew Danforth
|
||||
Mike Davis
|
||||
Shie Erlich
|
||||
Alexander von Gernler
|
||||
Artur Grabowski
|
||||
Aaron Hopkins
|
||||
Claudio Jeker
|
||||
Scott Lamb
|
||||
Adam Langley
|
||||
Philip Lewis
|
||||
David Libenzi
|
||||
Nick Mathewson
|
||||
Andrey Matveev
|
||||
Richard Nyberg
|
||||
Jon Oberheide
|
||||
Phil Oleson
|
||||
Dave Pacheco
|
||||
Tassilo von Parseval
|
||||
Pierre Phaneuf
|
||||
Jon Poland
|
||||
Bert JW Regeer
|
||||
Dug Song
|
||||
Taral
|
||||
|
||||
If I have forgotten your name, please contact me.
|
||||
247
extra/libevent/WIN32-Code/config.h
Normal file
247
extra/libevent/WIN32-Code/config.h
Normal file
@@ -0,0 +1,247 @@
|
||||
/* config.h. Generated by configure. */
|
||||
/* config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define if clock_gettime is available in libc */
|
||||
/* #undef DNS_USE_CPU_CLOCK_FOR_ID */
|
||||
|
||||
/* Define if no secure id variant is available */
|
||||
#define DNS_USE_FTIME_FOR_ID 1
|
||||
|
||||
/* Define if no secure id variant is available */
|
||||
/* #define DNS_USE_GETTIMEOFDAY_FOR_ID 1 */
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
/* #undef HAVE_CLOCK_GETTIME */
|
||||
|
||||
/* Define if /dev/poll is available */
|
||||
/* #undef HAVE_DEVPOLL */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
/* #undef HAVE_DLFCN_H */
|
||||
|
||||
/* Define if your system supports the epoll system calls */
|
||||
/* #undef HAVE_EPOLL */
|
||||
|
||||
/* Define to 1 if you have the `epoll_ctl' function. */
|
||||
/* #undef HAVE_EPOLL_CTL */
|
||||
|
||||
/* Define if your system supports event ports */
|
||||
/* #undef HAVE_EVENT_PORTS */
|
||||
|
||||
/* Define to 1 if you have the `fcntl' function. */
|
||||
/* #undef HAVE_FCNTL */
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
/* #undef HAVE_GETADDRINFO */
|
||||
|
||||
/* Define to 1 if you have the `getnameinfo' function. */
|
||||
/* #undef HAVE_GETNAMEINFO */
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
/* #define HAVE_GETTIMEOFDAY 1 */
|
||||
|
||||
/* Define to 1 if you have the `inet_ntop' function. */
|
||||
/* #undef HAVE_INET_NTOP */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
/* #undef HAVE_INTTYPES_H 1 */
|
||||
|
||||
/* Define to 1 if you have the `kqueue' function. */
|
||||
/* #undef HAVE_KQUEUE */
|
||||
|
||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||
/* #undef HAVE_LIBNSL */
|
||||
|
||||
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
||||
/* #undef HAVE_LIBRESOLV */
|
||||
|
||||
/* Define to 1 if you have the `rt' library (-lrt). */
|
||||
/* #undef HAVE_LIBRT */
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
/* #undef HAVE_LIBSOCKET */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in6.h> header file. */
|
||||
/* #undef HAVE_NETINET_IN6_H */
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
/* #undef HAVE_POLL */
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
/* #undef HAVE_POLL_H */
|
||||
|
||||
/* Define to 1 if you have the `port_create' function. */
|
||||
/* #undef HAVE_PORT_CREATE */
|
||||
|
||||
/* Define to 1 if you have the <port.h> header file. */
|
||||
/* #undef HAVE_PORT_H */
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
/* #undef HAVE_SELECT */
|
||||
|
||||
/* Define if F_SETFD is defined in <fcntl.h> */
|
||||
/* #undef HAVE_SETFD */
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
/* #undef HAVE_SIGACTION */
|
||||
|
||||
/* Define to 1 if you have the `signal' function. */
|
||||
#define HAVE_SIGNAL 1
|
||||
|
||||
/* Define to 1 if you have the <signal.h> header file. */
|
||||
#define HAVE_SIGNAL_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#define HAVE_STDARG_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
/* #define HAVE_STDINT_H 1 */
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
/* #undef HAVE_STRLCPY */
|
||||
|
||||
/* Define to 1 if you have the `strsep' function. */
|
||||
/* #undef HAVE_STRSEP */
|
||||
|
||||
/* Define to 1 if you have the `strtok_r' function. */
|
||||
/* #undef HAVE_STRTOK_R */
|
||||
|
||||
/* Define to 1 if the system has the type `struct in6_addr'. */
|
||||
#define HAVE_STRUCT_IN6_ADDR 1
|
||||
|
||||
/* Define to 1 if you have the <sys/devpoll.h> header file. */
|
||||
/* #undef HAVE_SYS_DEVPOLL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
||||
/* #undef HAVE_SYS_EPOLL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/event.h> header file. */
|
||||
/* #undef HAVE_SYS_EVENT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
/* #undef HAVE_SYS_IOCTL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/queue.h> header file. */
|
||||
/* #undef HAVE_SYS_QUEUE_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
/* #undef HAVE_SYS_SELECT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
/* #undef HAVE_SYS_SOCKET_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
/* #define HAVE_SYS_STAT_H 1 */
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
/* #define HAVE_SYS_TIME_H 1 */
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
/* #define HAVE_SYS_TYPES_H 1 */
|
||||
|
||||
/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
|
||||
/* #undef HAVE_TAILQFOREACH */
|
||||
|
||||
/* Define if timeradd is defined in <sys/time.h> */
|
||||
/* #undef HAVE_TIMERADD */
|
||||
|
||||
/* Define if timerclear is defined in <sys/time.h> */
|
||||
/* #define HAVE_TIMERCLEAR 1 */
|
||||
|
||||
/* Define if timercmp is defined in <sys/time.h> */
|
||||
#define HAVE_TIMERCMP 1
|
||||
|
||||
/* Define if timerisset is defined in <sys/time.h> */
|
||||
#define HAVE_TIMERISSET 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
/* #define HAVE_UNISTD_H 1 */
|
||||
|
||||
/* Define to 1 if you have the `vasprintf' function. */
|
||||
/* #undef HAVE_VASPRINTF */
|
||||
|
||||
/* Define if kqueue works correctly with pipes */
|
||||
/* #undef HAVE_WORKING_KQUEUE */
|
||||
|
||||
/* Name of package */
|
||||
#ifndef PACKAGE
|
||||
#define PACKAGE "libevent"
|
||||
#endif
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME ""
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING ""
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION ""
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.3.99-trunk"
|
||||
|
||||
#ifndef __func__
|
||||
/* Define to appropriate substitue if compiler doesnt have __func__ */
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1300
|
||||
#define __func__ "??"
|
||||
#else
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef pid_t */
|
||||
|
||||
/* Define to `unsigned' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* Define to unsigned int if you dont have it */
|
||||
#define socklen_t unsigned int
|
||||
|
||||
/* Define to `unsigned short' if <sys/types.h> does not define. */
|
||||
#define uint16_t unsigned short
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#define uint32_t unsigned int
|
||||
|
||||
/* Define to `unsigned long long' if <sys/types.h> does not define. */
|
||||
#define uint64_t __uint64_t
|
||||
|
||||
/* Define to `unsigned char' if <sys/types.h> does not define. */
|
||||
#define uint8_t unsigned char
|
||||
38
extra/libevent/WIN32-Code/misc.c
Normal file
38
extra/libevent/WIN32-Code/misc.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
/*our prototypes for timeval and timezone are in here, just in case the above
|
||||
headers don't have them*/
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Function: gettimeofday(struct timeval *, struct timezone *)
|
||||
*
|
||||
* Purpose: Get current time of day.
|
||||
*
|
||||
* Arguments: tv => Place to store the curent time of day.
|
||||
* tz => Ignored.
|
||||
*
|
||||
* Returns: 0 => Success.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||
struct _timeb tb;
|
||||
|
||||
if(tv == NULL)
|
||||
return -1;
|
||||
|
||||
_ftime(&tb);
|
||||
tv->tv_sec = (long) tb.time;
|
||||
tv->tv_usec = ((int) tb.millitm) * 1000;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
11
extra/libevent/WIN32-Code/misc.h
Normal file
11
extra/libevent/WIN32-Code/misc.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef MISC_H
|
||||
#define MISC_H
|
||||
|
||||
struct timezone;
|
||||
struct timeval;
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
int gettimeofday(struct timeval *,struct timezone *);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1354
extra/libevent/WIN32-Code/tree.h
Normal file
1354
extra/libevent/WIN32-Code/tree.h
Normal file
File diff suppressed because it is too large
Load Diff
471
extra/libevent/WIN32-Code/win32.c
Normal file
471
extra/libevent/WIN32-Code/win32.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2003 Michael A. Davis <mike@datanerds.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#include "./config.h"
|
||||
#else
|
||||
/* Avoid the windows/msvc thing. */
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define RB_AUGMENT(x) (void)(x)
|
||||
#include "./tree.h"
|
||||
#include "log.h"
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
|
||||
#define XFREE(ptr) do { if (ptr) free(ptr); } while(0)
|
||||
|
||||
extern struct event_list timequeue;
|
||||
extern struct event_list addqueue;
|
||||
#if 0
|
||||
extern struct event_list signalqueue;
|
||||
#endif
|
||||
|
||||
struct win_fd_set {
|
||||
u_int fd_count;
|
||||
SOCKET fd_array[1];
|
||||
};
|
||||
|
||||
int evsigcaught[NSIG];
|
||||
volatile sig_atomic_t signal_caught = 0;
|
||||
/* MSDN says this is required to handle SIGFPE */
|
||||
volatile double SIGFPE_REQ = 0.0f;
|
||||
|
||||
#if 0
|
||||
static void signal_handler(int sig);
|
||||
|
||||
void signal_process(void);
|
||||
int signal_recalc(void);
|
||||
#endif
|
||||
|
||||
struct event_entry {
|
||||
RB_ENTRY(event_entry) node;
|
||||
SOCKET sock;
|
||||
int read_pos;
|
||||
int write_pos;
|
||||
struct event *read_event;
|
||||
struct event *write_event;
|
||||
};
|
||||
|
||||
static int
|
||||
compare(struct event_entry *a, struct event_entry *b)
|
||||
{
|
||||
if (a->sock < b->sock)
|
||||
return -1;
|
||||
else if (a->sock > b->sock)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct win32op {
|
||||
int fd_setsz;
|
||||
struct win_fd_set *readset_in;
|
||||
struct win_fd_set *writeset_in;
|
||||
struct win_fd_set *readset_out;
|
||||
struct win_fd_set *writeset_out;
|
||||
struct win_fd_set *exset_out;
|
||||
RB_HEAD(event_map, event_entry) event_root;
|
||||
};
|
||||
|
||||
RB_PROTOTYPE(event_map, event_entry, node, compare);
|
||||
RB_GENERATE(event_map, event_entry, node, compare);
|
||||
|
||||
void *win32_init (struct event_base *);
|
||||
int win32_insert (void *, struct event *);
|
||||
int win32_del (void *, struct event *);
|
||||
int win32_dispatch (struct event_base *base, void *, struct timeval *);
|
||||
void win32_dealloc (struct event_base *, void *);
|
||||
|
||||
struct eventop win32ops = {
|
||||
"win32",
|
||||
win32_init,
|
||||
win32_insert,
|
||||
win32_del,
|
||||
win32_dispatch,
|
||||
win32_dealloc,
|
||||
0
|
||||
};
|
||||
|
||||
#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
|
||||
|
||||
static int
|
||||
realloc_fd_sets(struct win32op *op, size_t new_size)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
assert(new_size >= op->readset_in->fd_count &&
|
||||
new_size >= op->writeset_in->fd_count);
|
||||
assert(new_size >= 1);
|
||||
|
||||
size = FD_SET_ALLOC_SIZE(new_size);
|
||||
if (!(op->readset_in = realloc(op->readset_in, size)))
|
||||
return (-1);
|
||||
if (!(op->writeset_in = realloc(op->writeset_in, size)))
|
||||
return (-1);
|
||||
if (!(op->readset_out = realloc(op->readset_out, size)))
|
||||
return (-1);
|
||||
if (!(op->exset_out = realloc(op->exset_out, size)))
|
||||
return (-1);
|
||||
if (!(op->writeset_out = realloc(op->writeset_out, size)))
|
||||
return (-1);
|
||||
op->fd_setsz = (int)new_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
timeval_to_ms(struct timeval *tv)
|
||||
{
|
||||
return ((tv->tv_sec * 1000) + (tv->tv_usec / 1000));
|
||||
}
|
||||
|
||||
static struct event_entry*
|
||||
get_event_entry(struct win32op *op, SOCKET s, int create)
|
||||
{
|
||||
struct event_entry key, *val;
|
||||
key.sock = s;
|
||||
val = RB_FIND(event_map, &op->event_root, &key);
|
||||
if (val || !create)
|
||||
return val;
|
||||
if (!(val = calloc(1, sizeof(struct event_entry)))) {
|
||||
event_warn("%s: calloc", __func__);
|
||||
return NULL;
|
||||
}
|
||||
val->sock = s;
|
||||
val->read_pos = val->write_pos = -1;
|
||||
RB_INSERT(event_map, &op->event_root, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static int
|
||||
do_fd_set(struct win32op *op, struct event_entry *ent, int read)
|
||||
{
|
||||
SOCKET s = ent->sock;
|
||||
struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
|
||||
if (read) {
|
||||
if (ent->read_pos >= 0)
|
||||
return (0);
|
||||
} else {
|
||||
if (ent->write_pos >= 0)
|
||||
return (0);
|
||||
}
|
||||
if (set->fd_count == op->fd_setsz) {
|
||||
if (realloc_fd_sets(op, op->fd_setsz*2))
|
||||
return (-1);
|
||||
/* set pointer will have changed and needs reiniting! */
|
||||
set = read ? op->readset_in : op->writeset_in;
|
||||
}
|
||||
set->fd_array[set->fd_count] = s;
|
||||
if (read)
|
||||
ent->read_pos = set->fd_count;
|
||||
else
|
||||
ent->write_pos = set->fd_count;
|
||||
return (set->fd_count++);
|
||||
}
|
||||
|
||||
static int
|
||||
do_fd_clear(struct win32op *op, struct event_entry *ent, int read)
|
||||
{
|
||||
int i;
|
||||
struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
|
||||
if (read) {
|
||||
i = ent->read_pos;
|
||||
ent->read_pos = -1;
|
||||
} else {
|
||||
i = ent->write_pos;
|
||||
ent->write_pos = -1;
|
||||
}
|
||||
if (i < 0)
|
||||
return (0);
|
||||
if (--set->fd_count != i) {
|
||||
struct event_entry *ent2;
|
||||
SOCKET s2;
|
||||
s2 = set->fd_array[i] = set->fd_array[set->fd_count];
|
||||
ent2 = get_event_entry(op, s2, 0);
|
||||
if (!ent) /* This indicates a bug. */
|
||||
return (0);
|
||||
if (read)
|
||||
ent2->read_pos = i;
|
||||
else
|
||||
ent2->write_pos = i;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define NEVENT 64
|
||||
void *
|
||||
win32_init(struct event_base *_base)
|
||||
{
|
||||
struct win32op *winop;
|
||||
size_t size;
|
||||
if (!(winop = calloc(1, sizeof(struct win32op))))
|
||||
return NULL;
|
||||
winop->fd_setsz = NEVENT;
|
||||
size = FD_SET_ALLOC_SIZE(NEVENT);
|
||||
if (!(winop->readset_in = malloc(size)))
|
||||
goto err;
|
||||
if (!(winop->writeset_in = malloc(size)))
|
||||
goto err;
|
||||
if (!(winop->readset_out = malloc(size)))
|
||||
goto err;
|
||||
if (!(winop->writeset_out = malloc(size)))
|
||||
goto err;
|
||||
if (!(winop->exset_out = malloc(size)))
|
||||
goto err;
|
||||
RB_INIT(&winop->event_root);
|
||||
winop->readset_in->fd_count = winop->writeset_in->fd_count = 0;
|
||||
winop->readset_out->fd_count = winop->writeset_out->fd_count
|
||||
= winop->exset_out->fd_count = 0;
|
||||
|
||||
evsignal_init(_base);
|
||||
|
||||
return (winop);
|
||||
err:
|
||||
XFREE(winop->readset_in);
|
||||
XFREE(winop->writeset_in);
|
||||
XFREE(winop->readset_out);
|
||||
XFREE(winop->writeset_out);
|
||||
XFREE(winop->exset_out);
|
||||
XFREE(winop);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
win32_insert(void *op, struct event *ev)
|
||||
{
|
||||
struct win32op *win32op = op;
|
||||
struct event_entry *ent;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL) {
|
||||
return (evsignal_add(ev));
|
||||
}
|
||||
if (!(ev->ev_events & (EV_READ|EV_WRITE)))
|
||||
return (0);
|
||||
ent = get_event_entry(win32op, ev->ev_fd, 1);
|
||||
if (!ent)
|
||||
return (-1); /* out of memory */
|
||||
|
||||
event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd));
|
||||
if (ev->ev_events & EV_READ) {
|
||||
if (do_fd_set(win32op, ent, 1)<0)
|
||||
return (-1);
|
||||
ent->read_event = ev;
|
||||
}
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
if (do_fd_set(win32op, ent, 0)<0)
|
||||
return (-1);
|
||||
ent->write_event = ev;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
win32_del(void *op, struct event *ev)
|
||||
{
|
||||
struct win32op *win32op = op;
|
||||
struct event_entry *ent;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_del(ev));
|
||||
|
||||
if (!(ent = get_event_entry(win32op, ev->ev_fd, 0)))
|
||||
return (-1);
|
||||
event_debug(("%s: Removing event for %d", __func__, ev->ev_fd));
|
||||
if (ev == ent->read_event) {
|
||||
do_fd_clear(win32op, ent, 1);
|
||||
ent->read_event = NULL;
|
||||
}
|
||||
if (ev == ent->write_event) {
|
||||
do_fd_clear(win32op, ent, 0);
|
||||
ent->write_event = NULL;
|
||||
}
|
||||
if (!ent->read_event && !ent->write_event) {
|
||||
RB_REMOVE(event_map, &win32op->event_root, ent);
|
||||
free(ent);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in)
|
||||
{
|
||||
out->fd_count = in->fd_count;
|
||||
memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET)));
|
||||
}
|
||||
|
||||
/*
|
||||
static void dump_fd_set(struct win_fd_set *s)
|
||||
{
|
||||
unsigned int i;
|
||||
printf("[ ");
|
||||
for(i=0;i<s->fd_count;++i)
|
||||
printf("%d ",(int)s->fd_array[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
*/
|
||||
|
||||
int
|
||||
win32_dispatch(struct event_base *base, void *op,
|
||||
struct timeval *tv)
|
||||
{
|
||||
struct win32op *win32op = op;
|
||||
int res = 0;
|
||||
u_int i;
|
||||
int fd_count;
|
||||
|
||||
fd_set_copy(win32op->readset_out, win32op->readset_in);
|
||||
fd_set_copy(win32op->exset_out, win32op->readset_in);
|
||||
fd_set_copy(win32op->writeset_out, win32op->writeset_in);
|
||||
|
||||
fd_count =
|
||||
(win32op->readset_out->fd_count > win32op->writeset_out->fd_count) ?
|
||||
win32op->readset_out->fd_count : win32op->writeset_out->fd_count;
|
||||
|
||||
if (!fd_count) {
|
||||
/* Windows doesn't like you to call select() with no sockets */
|
||||
Sleep(timeval_to_ms(tv));
|
||||
evsignal_process(base);
|
||||
return (0);
|
||||
}
|
||||
|
||||
res = select(fd_count,
|
||||
(struct fd_set*)win32op->readset_out,
|
||||
(struct fd_set*)win32op->writeset_out,
|
||||
(struct fd_set*)win32op->exset_out, tv);
|
||||
|
||||
event_debug(("%s: select returned %d", __func__, res));
|
||||
|
||||
if(res <= 0) {
|
||||
evsignal_process(base);
|
||||
return res;
|
||||
} else if (base->sig.evsignal_caught) {
|
||||
evsignal_process(base);
|
||||
}
|
||||
|
||||
for (i=0; i<win32op->readset_out->fd_count; ++i) {
|
||||
struct event_entry *ent;
|
||||
SOCKET s = win32op->readset_out->fd_array[i];
|
||||
if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event)
|
||||
event_active(ent->read_event, EV_READ, 1);
|
||||
}
|
||||
for (i=0; i<win32op->exset_out->fd_count; ++i) {
|
||||
struct event_entry *ent;
|
||||
SOCKET s = win32op->exset_out->fd_array[i];
|
||||
if ((ent = get_event_entry(win32op, s, 0)) && ent->read_event)
|
||||
event_active(ent->read_event, EV_READ, 1);
|
||||
}
|
||||
for (i=0; i<win32op->writeset_out->fd_count; ++i) {
|
||||
struct event_entry *ent;
|
||||
SOCKET s = win32op->writeset_out->fd_array[i];
|
||||
if ((ent = get_event_entry(win32op, s, 0)) && ent->write_event)
|
||||
event_active(ent->write_event, EV_WRITE, 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (signal_recalc() == -1)
|
||||
return (-1);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
win32_dealloc(struct event_base *_base, void *arg)
|
||||
{
|
||||
struct win32op *win32op = arg;
|
||||
|
||||
evsignal_dealloc(_base);
|
||||
if (win32op->readset_in)
|
||||
free(win32op->readset_in);
|
||||
if (win32op->writeset_in)
|
||||
free(win32op->writeset_in);
|
||||
if (win32op->readset_out)
|
||||
free(win32op->readset_out);
|
||||
if (win32op->writeset_out)
|
||||
free(win32op->writeset_out);
|
||||
if (win32op->exset_out)
|
||||
free(win32op->exset_out);
|
||||
/* XXXXX free the tree. */
|
||||
|
||||
memset(win32op, 0, sizeof(win32op));
|
||||
free(win32op);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
evsigcaught[sig]++;
|
||||
signal_caught = 1;
|
||||
}
|
||||
|
||||
int
|
||||
signal_recalc(void)
|
||||
{
|
||||
struct event *ev;
|
||||
|
||||
/* Reinstall our signal handler. */
|
||||
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
|
||||
if((int)signal(EVENT_SIGNAL(ev), signal_handler) == -1)
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
signal_process(void)
|
||||
{
|
||||
struct event *ev;
|
||||
short ncalls;
|
||||
|
||||
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
|
||||
ncalls = evsigcaught[EVENT_SIGNAL(ev)];
|
||||
if (ncalls) {
|
||||
if (!(ev->ev_events & EV_PERSIST))
|
||||
event_del(ev);
|
||||
event_active(ev, EV_SIGNAL, ncalls);
|
||||
}
|
||||
}
|
||||
|
||||
memset(evsigcaught, 0, sizeof(evsigcaught));
|
||||
signal_caught = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
455
extra/libevent/buffer.c
Normal file
455
extra/libevent/buffer.c
Normal file
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VASPRINTF
|
||||
/* If we have vasprintf, we need to define this before we include stdio.h. */
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "config.h"
|
||||
|
||||
struct evbuffer *
|
||||
evbuffer_new(void)
|
||||
{
|
||||
struct evbuffer *buffer;
|
||||
|
||||
buffer = calloc(1, sizeof(struct evbuffer));
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
evbuffer_free(struct evbuffer *buffer)
|
||||
{
|
||||
if (buffer->orig_buffer != NULL)
|
||||
free(buffer->orig_buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a destructive add. The data from one buffer moves into
|
||||
* the other buffer.
|
||||
*/
|
||||
|
||||
#define SWAP(x,y) do { \
|
||||
(x)->buffer = (y)->buffer; \
|
||||
(x)->orig_buffer = (y)->orig_buffer; \
|
||||
(x)->misalign = (y)->misalign; \
|
||||
(x)->totallen = (y)->totallen; \
|
||||
(x)->off = (y)->off; \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Short cut for better performance */
|
||||
if (outbuf->off == 0) {
|
||||
struct evbuffer tmp;
|
||||
size_t oldoff = inbuf->off;
|
||||
|
||||
/* Swap them directly */
|
||||
SWAP(&tmp, outbuf);
|
||||
SWAP(outbuf, inbuf);
|
||||
SWAP(inbuf, &tmp);
|
||||
|
||||
/*
|
||||
* Optimization comes with a price; we need to notify the
|
||||
* buffer if necessary of the changes. oldoff is the amount
|
||||
* of data that we transfered from inbuf to outbuf
|
||||
*/
|
||||
if (inbuf->off != oldoff && inbuf->cb != NULL)
|
||||
(*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
|
||||
if (oldoff && outbuf->cb != NULL)
|
||||
(*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
|
||||
if (res == 0) {
|
||||
/* We drain the input buffer on success */
|
||||
evbuffer_drain(inbuf, inbuf->off);
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
|
||||
{
|
||||
char *buffer;
|
||||
size_t space;
|
||||
size_t oldoff = buf->off;
|
||||
int sz;
|
||||
va_list aq;
|
||||
|
||||
/* make sure that at least some space is available */
|
||||
evbuffer_expand(buf, 64);
|
||||
for (;;) {
|
||||
size_t used = buf->misalign + buf->off;
|
||||
buffer = (char *)buf->buffer + buf->off;
|
||||
assert(buf->totallen >= used);
|
||||
space = buf->totallen - used;
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
|
||||
#endif
|
||||
va_copy(aq, ap);
|
||||
|
||||
#ifdef WIN32
|
||||
sz = _vsnprintf(buffer, space - 1, fmt, aq);
|
||||
buffer[space - 1] = '\0';
|
||||
#else
|
||||
sz = vsnprintf(buffer, space, fmt, aq);
|
||||
#endif
|
||||
|
||||
va_end(aq);
|
||||
|
||||
if (sz < 0)
|
||||
return (-1);
|
||||
if ((size_t)sz < space) {
|
||||
buf->off += sz;
|
||||
if (buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
return (sz);
|
||||
}
|
||||
if (evbuffer_expand(buf, sz + 1) == -1)
|
||||
return (-1);
|
||||
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
|
||||
{
|
||||
int res = -1;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
res = evbuffer_add_vprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/* Reads data from an event buffer and drains the bytes read */
|
||||
|
||||
int
|
||||
evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
|
||||
{
|
||||
size_t nread = datlen;
|
||||
if (nread >= buf->off)
|
||||
nread = buf->off;
|
||||
|
||||
memcpy(data, buf->buffer, nread);
|
||||
evbuffer_drain(buf, nread);
|
||||
|
||||
return (int)(nread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
|
||||
* The returned buffer needs to be freed by the called.
|
||||
*/
|
||||
|
||||
char *
|
||||
evbuffer_readline(struct evbuffer *buffer)
|
||||
{
|
||||
u_char *data = EVBUFFER_DATA(buffer);
|
||||
size_t len = EVBUFFER_LENGTH(buffer);
|
||||
char *line;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (data[i] == '\r' || data[i] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
return (NULL);
|
||||
|
||||
if ((line = malloc(i + 1)) == NULL) {
|
||||
fprintf(stderr, "%s: out of memory\n", __func__);
|
||||
evbuffer_drain(buffer, i);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memcpy(line, data, i);
|
||||
line[i] = '\0';
|
||||
|
||||
/*
|
||||
* Some protocols terminate a line with '\r\n', so check for
|
||||
* that, too.
|
||||
*/
|
||||
if ( i < len - 1 ) {
|
||||
char fch = data[i], sch = data[i+1];
|
||||
|
||||
/* Drain one more character if needed */
|
||||
if ( (sch == '\r' || sch == '\n') && sch != fch )
|
||||
i += 1;
|
||||
}
|
||||
|
||||
evbuffer_drain(buffer, i + 1);
|
||||
|
||||
return (line);
|
||||
}
|
||||
|
||||
/* Adds data to an event buffer */
|
||||
|
||||
static void
|
||||
evbuffer_align(struct evbuffer *buf)
|
||||
{
|
||||
memmove(buf->orig_buffer, buf->buffer, buf->off);
|
||||
buf->buffer = buf->orig_buffer;
|
||||
buf->misalign = 0;
|
||||
}
|
||||
|
||||
/* Expands the available space in the event buffer to at least datlen */
|
||||
|
||||
int
|
||||
evbuffer_expand(struct evbuffer *buf, size_t datlen)
|
||||
{
|
||||
size_t need = buf->misalign + buf->off + datlen;
|
||||
|
||||
/* If we can fit all the data, then we don't have to do anything */
|
||||
if (buf->totallen >= need)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the misalignment fulfills our data needs, we just force an
|
||||
* alignment to happen. Afterwards, we have enough space.
|
||||
*/
|
||||
if (buf->misalign >= datlen) {
|
||||
evbuffer_align(buf);
|
||||
} else {
|
||||
void *newbuf;
|
||||
size_t length = buf->totallen;
|
||||
|
||||
if (length < 256)
|
||||
length = 256;
|
||||
while (length < need)
|
||||
length <<= 1;
|
||||
|
||||
if (buf->orig_buffer != buf->buffer)
|
||||
evbuffer_align(buf);
|
||||
if ((newbuf = realloc(buf->buffer, length)) == NULL)
|
||||
return (-1);
|
||||
|
||||
buf->orig_buffer = buf->buffer = newbuf;
|
||||
buf->totallen = length;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
|
||||
{
|
||||
size_t need = buf->misalign + buf->off + datlen;
|
||||
size_t oldoff = buf->off;
|
||||
|
||||
if (buf->totallen < need) {
|
||||
if (evbuffer_expand(buf, datlen) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(buf->buffer + buf->off, data, datlen);
|
||||
buf->off += datlen;
|
||||
|
||||
if (datlen && buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
evbuffer_drain(struct evbuffer *buf, size_t len)
|
||||
{
|
||||
size_t oldoff = buf->off;
|
||||
|
||||
if (len >= buf->off) {
|
||||
buf->off = 0;
|
||||
buf->buffer = buf->orig_buffer;
|
||||
buf->misalign = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buf->buffer += len;
|
||||
buf->misalign += len;
|
||||
|
||||
buf->off -= len;
|
||||
|
||||
done:
|
||||
/* Tell someone about changes in this buffer */
|
||||
if (buf->off != oldoff && buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads data from a file descriptor into a buffer.
|
||||
*/
|
||||
|
||||
#define EVBUFFER_MAX_READ 4096
|
||||
|
||||
int
|
||||
evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
|
||||
{
|
||||
u_char *p;
|
||||
size_t oldoff = buf->off;
|
||||
int n = EVBUFFER_MAX_READ;
|
||||
|
||||
#if defined(FIONREAD)
|
||||
#ifdef WIN32
|
||||
long lng = (long)n;
|
||||
if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) {
|
||||
#else
|
||||
if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
|
||||
#endif
|
||||
n = EVBUFFER_MAX_READ;
|
||||
} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
|
||||
/*
|
||||
* It's possible that a lot of data is available for
|
||||
* reading. We do not want to exhaust resources
|
||||
* before the reader has a chance to do something
|
||||
* about it. If the reader does not tell us how much
|
||||
* data we should read, we artifically limit it.
|
||||
*/
|
||||
if ((size_t)n > (buf->totallen << 2))
|
||||
n = (int)(buf->totallen << 2);
|
||||
if (n < EVBUFFER_MAX_READ)
|
||||
n = EVBUFFER_MAX_READ;
|
||||
}
|
||||
#endif
|
||||
if (howmuch < 0 || howmuch > n)
|
||||
howmuch = n;
|
||||
|
||||
/* If we don't have FIONREAD, we might waste some space here */
|
||||
if (evbuffer_expand(buf, howmuch) == -1)
|
||||
return (-1);
|
||||
|
||||
/* We can append new data at this point */
|
||||
p = buf->buffer + buf->off;
|
||||
|
||||
#ifndef WIN32
|
||||
n = read(fd, p, howmuch);
|
||||
#else
|
||||
n = recv(fd, p, howmuch, 0);
|
||||
#endif
|
||||
if (n == -1)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
return (0);
|
||||
|
||||
buf->off += n;
|
||||
|
||||
/* Tell someone about changes in this buffer */
|
||||
if (buf->off != oldoff && buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_write(struct evbuffer *buffer, int fd)
|
||||
{
|
||||
int n;
|
||||
|
||||
#ifndef WIN32
|
||||
n = write(fd, buffer->buffer, buffer->off);
|
||||
#else
|
||||
n = send(fd, buffer->buffer, (int)buffer->off, 0);
|
||||
#endif
|
||||
if (n == -1)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
return (0);
|
||||
evbuffer_drain(buffer, n);
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
u_char *
|
||||
evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
|
||||
{
|
||||
u_char *search = buffer->buffer, *end = search + buffer->off;
|
||||
u_char *p;
|
||||
|
||||
while (search < end &&
|
||||
(p = memchr(search, *what, end - search)) != NULL) {
|
||||
if (p + len > end)
|
||||
break;
|
||||
if (memcmp(p, what, len) == 0)
|
||||
return (p);
|
||||
search = p + 1;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void evbuffer_setcb(struct evbuffer *buffer,
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *),
|
||||
void *cbarg)
|
||||
{
|
||||
buffer->cb = cb;
|
||||
buffer->cbarg = cbarg;
|
||||
}
|
||||
163
extra/libevent/compat/sys/_time.h
Normal file
163
extra/libevent/compat/sys/_time.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* $OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $ */
|
||||
/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1982, 1986, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)time.h 8.2 (Berkeley) 7/10/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_TIME_H_
|
||||
#define _SYS_TIME_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* Structure returned by gettimeofday(2) system call,
|
||||
* and used in other calls.
|
||||
*/
|
||||
struct timeval {
|
||||
long tv_sec; /* seconds */
|
||||
long tv_usec; /* and microseconds */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure defined by POSIX.1b to be like a timeval.
|
||||
*/
|
||||
struct timespec {
|
||||
time_t tv_sec; /* seconds */
|
||||
long tv_nsec; /* and nanoseconds */
|
||||
};
|
||||
|
||||
#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
|
||||
(ts)->tv_sec = (tv)->tv_sec; \
|
||||
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
|
||||
}
|
||||
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
|
||||
(tv)->tv_sec = (ts)->tv_sec; \
|
||||
(tv)->tv_usec = (ts)->tv_nsec / 1000; \
|
||||
}
|
||||
|
||||
struct timezone {
|
||||
int tz_minuteswest; /* minutes west of Greenwich */
|
||||
int tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
#define DST_NONE 0 /* not on dst */
|
||||
#define DST_USA 1 /* USA style dst */
|
||||
#define DST_AUST 2 /* Australian style dst */
|
||||
#define DST_WET 3 /* Western European dst */
|
||||
#define DST_MET 4 /* Middle European dst */
|
||||
#define DST_EET 5 /* Eastern European dst */
|
||||
#define DST_CAN 6 /* Canada */
|
||||
|
||||
/* Operations on timevals. */
|
||||
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
|
||||
#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
|
||||
#define timercmp(tvp, uvp, cmp) \
|
||||
(((tvp)->tv_sec == (uvp)->tv_sec) ? \
|
||||
((tvp)->tv_usec cmp (uvp)->tv_usec) : \
|
||||
((tvp)->tv_sec cmp (uvp)->tv_sec))
|
||||
#define timeradd(tvp, uvp, vvp) \
|
||||
do { \
|
||||
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
|
||||
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
|
||||
if ((vvp)->tv_usec >= 1000000) { \
|
||||
(vvp)->tv_sec++; \
|
||||
(vvp)->tv_usec -= 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
#define timersub(tvp, uvp, vvp) \
|
||||
do { \
|
||||
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
|
||||
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
|
||||
if ((vvp)->tv_usec < 0) { \
|
||||
(vvp)->tv_sec--; \
|
||||
(vvp)->tv_usec += 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Operations on timespecs. */
|
||||
#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0
|
||||
#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
|
||||
#define timespeccmp(tsp, usp, cmp) \
|
||||
(((tsp)->tv_sec == (usp)->tv_sec) ? \
|
||||
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
|
||||
((tsp)->tv_sec cmp (usp)->tv_sec))
|
||||
#define timespecadd(tsp, usp, vsp) \
|
||||
do { \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec >= 1000000000L) { \
|
||||
(vsp)->tv_sec++; \
|
||||
(vsp)->tv_nsec -= 1000000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
#define timespecsub(tsp, usp, vsp) \
|
||||
do { \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec < 0) { \
|
||||
(vsp)->tv_sec--; \
|
||||
(vsp)->tv_nsec += 1000000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Names of the interval timers, and structure
|
||||
* defining a timer setting.
|
||||
*/
|
||||
#define ITIMER_REAL 0
|
||||
#define ITIMER_VIRTUAL 1
|
||||
#define ITIMER_PROF 2
|
||||
|
||||
struct itimerval {
|
||||
struct timeval it_interval; /* timer interval */
|
||||
struct timeval it_value; /* current value */
|
||||
};
|
||||
|
||||
/*
|
||||
* Getkerninfo clock information structure
|
||||
*/
|
||||
struct clockinfo {
|
||||
int hz; /* clock frequency */
|
||||
int tick; /* micro-seconds per hz tick */
|
||||
int tickadj; /* clock skew rate for adjtime() */
|
||||
int stathz; /* statistics clock frequency */
|
||||
int profhz; /* profiling clock frequency */
|
||||
};
|
||||
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_VIRTUAL 1
|
||||
#define CLOCK_PROF 2
|
||||
|
||||
#define TIMER_RELTIME 0x0 /* relative timer */
|
||||
#define TIMER_ABSTIME 0x1 /* absolute timer */
|
||||
|
||||
/* --- stuff got cut here - niels --- */
|
||||
|
||||
#endif /* !_SYS_TIME_H_ */
|
||||
488
extra/libevent/compat/sys/queue.h
Normal file
488
extra/libevent/compat/sys/queue.h
Normal 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, field, headname) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_END(head) ((void *)(head))
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define CIRCLEQ_EMPTY(head) \
|
||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = CIRCLEQ_FIRST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = CIRCLEQ_LAST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
||||
677
extra/libevent/compat/sys/tree.h
Normal file
677
extra/libevent/compat/sys/tree.h
Normal 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_ */
|
||||
421
extra/libevent/devpoll.c
Normal file
421
extra/libevent/devpoll.c
Normal file
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
* Copyright 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DEVPOLL
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/devpoll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "evsignal.h"
|
||||
#include "log.h"
|
||||
|
||||
/* due to limitations in the devpoll interface, we need to keep track of
|
||||
* all file descriptors outself.
|
||||
*/
|
||||
struct evdevpoll {
|
||||
struct event *evread;
|
||||
struct event *evwrite;
|
||||
};
|
||||
|
||||
struct devpollop {
|
||||
struct evdevpoll *fds;
|
||||
int nfds;
|
||||
struct pollfd *events;
|
||||
int nevents;
|
||||
int dpfd;
|
||||
struct pollfd *changes;
|
||||
int nchanges;
|
||||
};
|
||||
|
||||
static void *devpoll_init (struct event_base *);
|
||||
static int devpoll_add (void *, struct event *);
|
||||
static int devpoll_del (void *, struct event *);
|
||||
static int devpoll_dispatch (struct event_base *, void *, struct timeval *);
|
||||
static void devpoll_dealloc (struct event_base *, void *);
|
||||
|
||||
struct eventop devpollops = {
|
||||
"devpoll",
|
||||
devpoll_init,
|
||||
devpoll_add,
|
||||
devpoll_del,
|
||||
devpoll_dispatch,
|
||||
devpoll_dealloc,
|
||||
1 /* need reinit */
|
||||
};
|
||||
|
||||
#define NEVENT 32000
|
||||
|
||||
static int
|
||||
devpoll_commit(struct devpollop *devpollop)
|
||||
{
|
||||
/*
|
||||
* Due to a bug in Solaris, we have to use pwrite with an offset of 0.
|
||||
* Write is limited to 2GB of data, until it will fail.
|
||||
*/
|
||||
if (pwrite(devpollop->dpfd, devpollop->changes,
|
||||
sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
|
||||
return(-1);
|
||||
|
||||
devpollop->nchanges = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
devpoll_queue(struct devpollop *devpollop, int fd, int events) {
|
||||
struct pollfd *pfd;
|
||||
|
||||
if (devpollop->nchanges >= devpollop->nevents) {
|
||||
/*
|
||||
* Change buffer is full, must commit it to /dev/poll before
|
||||
* adding more
|
||||
*/
|
||||
if (devpoll_commit(devpollop) != 0)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
pfd = &devpollop->changes[devpollop->nchanges++];
|
||||
pfd->fd = fd;
|
||||
pfd->events = events;
|
||||
pfd->revents = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void *
|
||||
devpoll_init(struct event_base *base)
|
||||
{
|
||||
int dpfd, nfiles = NEVENT;
|
||||
struct rlimit rl;
|
||||
struct devpollop *devpollop;
|
||||
|
||||
/* Disable devpoll when this environment variable is set */
|
||||
if (getenv("EVENT_NODEVPOLL"))
|
||||
return (NULL);
|
||||
|
||||
if (!(devpollop = calloc(1, sizeof(struct devpollop))))
|
||||
return (NULL);
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
|
||||
(unsigned long long) rl.rlim_cur != (unsigned long long) RLIM_INFINITY)
|
||||
nfiles = rl.rlim_cur - 1;
|
||||
|
||||
/* Initialize the kernel queue */
|
||||
if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
|
||||
event_warn("open: /dev/poll");
|
||||
free(devpollop);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
devpollop->dpfd = dpfd;
|
||||
|
||||
/* Initialize fields */
|
||||
devpollop->events = calloc(nfiles, sizeof(struct pollfd));
|
||||
if (devpollop->events == NULL) {
|
||||
free(devpollop);
|
||||
close(dpfd);
|
||||
return (NULL);
|
||||
}
|
||||
devpollop->nevents = nfiles;
|
||||
|
||||
devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
|
||||
if (devpollop->fds == NULL) {
|
||||
free(devpollop->events);
|
||||
free(devpollop);
|
||||
close(dpfd);
|
||||
return (NULL);
|
||||
}
|
||||
devpollop->nfds = nfiles;
|
||||
|
||||
devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
|
||||
if (devpollop->changes == NULL) {
|
||||
free(devpollop->fds);
|
||||
free(devpollop->events);
|
||||
free(devpollop);
|
||||
close(dpfd);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
evsignal_init(base);
|
||||
|
||||
return (devpollop);
|
||||
}
|
||||
|
||||
static int
|
||||
devpoll_recalc(struct event_base *base, void *arg, int max)
|
||||
{
|
||||
struct devpollop *devpollop = arg;
|
||||
|
||||
if (max > devpollop->nfds) {
|
||||
struct evdevpoll *fds;
|
||||
int nfds;
|
||||
|
||||
nfds = devpollop->nfds;
|
||||
while (nfds < max)
|
||||
nfds <<= 1;
|
||||
|
||||
fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
|
||||
if (fds == NULL) {
|
||||
event_warn("realloc");
|
||||
return (-1);
|
||||
}
|
||||
devpollop->fds = fds;
|
||||
memset(fds + devpollop->nfds, 0,
|
||||
(nfds - devpollop->nfds) * sizeof(struct evdevpoll));
|
||||
devpollop->nfds = nfds;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
|
||||
{
|
||||
struct devpollop *devpollop = arg;
|
||||
struct pollfd *events = devpollop->events;
|
||||
struct dvpoll dvp;
|
||||
struct evdevpoll *evdp;
|
||||
int i, res, timeout = -1;
|
||||
|
||||
if (devpollop->nchanges)
|
||||
devpoll_commit(devpollop);
|
||||
|
||||
if (tv != NULL)
|
||||
timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
|
||||
|
||||
dvp.dp_fds = devpollop->events;
|
||||
dvp.dp_nfds = devpollop->nevents;
|
||||
dvp.dp_timeout = timeout;
|
||||
|
||||
res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
|
||||
|
||||
if (res == -1) {
|
||||
if (errno != EINTR) {
|
||||
event_warn("ioctl: DP_POLL");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
evsignal_process(base);
|
||||
return (0);
|
||||
} else if (base->sig.evsignal_caught) {
|
||||
evsignal_process(base);
|
||||
}
|
||||
|
||||
event_debug(("%s: devpoll_wait reports %d", __func__, res));
|
||||
|
||||
for (i = 0; i < res; i++) {
|
||||
int which = 0;
|
||||
int what = events[i].revents;
|
||||
struct event *evread = NULL, *evwrite = NULL;
|
||||
|
||||
assert(events[i].fd < devpollop->nfds);
|
||||
evdp = &devpollop->fds[events[i].fd];
|
||||
|
||||
if (what & POLLHUP)
|
||||
what |= POLLIN | POLLOUT;
|
||||
else if (what & POLLERR)
|
||||
what |= POLLIN | POLLOUT;
|
||||
|
||||
if (what & POLLIN) {
|
||||
evread = evdp->evread;
|
||||
which |= EV_READ;
|
||||
}
|
||||
|
||||
if (what & POLLOUT) {
|
||||
evwrite = evdp->evwrite;
|
||||
which |= EV_WRITE;
|
||||
}
|
||||
|
||||
if (!which)
|
||||
continue;
|
||||
|
||||
if (evread != NULL && !(evread->ev_events & EV_PERSIST))
|
||||
event_del(evread);
|
||||
if (evwrite != NULL && evwrite != evread &&
|
||||
!(evwrite->ev_events & EV_PERSIST))
|
||||
event_del(evwrite);
|
||||
|
||||
if (evread != NULL)
|
||||
event_active(evread, EV_READ, 1);
|
||||
if (evwrite != NULL)
|
||||
event_active(evwrite, EV_WRITE, 1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
devpoll_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct devpollop *devpollop = arg;
|
||||
struct evdevpoll *evdp;
|
||||
int fd, events;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_add(ev));
|
||||
|
||||
fd = ev->ev_fd;
|
||||
if (fd >= devpollop->nfds) {
|
||||
/* Extend the file descriptor array as necessary */
|
||||
if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
|
||||
return (-1);
|
||||
}
|
||||
evdp = &devpollop->fds[fd];
|
||||
|
||||
/*
|
||||
* It's not necessary to OR the existing read/write events that we
|
||||
* are currently interested in with the new event we are adding.
|
||||
* The /dev/poll driver ORs any new events with the existing events
|
||||
* that it has cached for the fd.
|
||||
*/
|
||||
|
||||
events = 0;
|
||||
if (ev->ev_events & EV_READ) {
|
||||
if (evdp->evread && evdp->evread != ev) {
|
||||
/* There is already a different read event registered */
|
||||
return(-1);
|
||||
}
|
||||
events |= POLLIN;
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
if (evdp->evwrite && evdp->evwrite != ev) {
|
||||
/* There is already a different write event registered */
|
||||
return(-1);
|
||||
}
|
||||
events |= POLLOUT;
|
||||
}
|
||||
|
||||
if (devpoll_queue(devpollop, fd, events) != 0)
|
||||
return(-1);
|
||||
|
||||
/* Update events responsible */
|
||||
if (ev->ev_events & EV_READ)
|
||||
evdp->evread = ev;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
evdp->evwrite = ev;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
devpoll_del(void *arg, struct event *ev)
|
||||
{
|
||||
struct devpollop *devpollop = arg;
|
||||
struct evdevpoll *evdp;
|
||||
int fd, events;
|
||||
int needwritedelete = 1, needreaddelete = 1;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_del(ev));
|
||||
|
||||
fd = ev->ev_fd;
|
||||
if (fd >= devpollop->nfds)
|
||||
return (0);
|
||||
evdp = &devpollop->fds[fd];
|
||||
|
||||
events = 0;
|
||||
if (ev->ev_events & EV_READ)
|
||||
events |= POLLIN;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
events |= POLLOUT;
|
||||
|
||||
/*
|
||||
* The only way to remove an fd from the /dev/poll monitored set is
|
||||
* to use POLLREMOVE by itself. This removes ALL events for the fd
|
||||
* provided so if we care about two events and are only removing one
|
||||
* we must re-add the other event after POLLREMOVE.
|
||||
*/
|
||||
|
||||
if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
|
||||
return(-1);
|
||||
|
||||
if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
|
||||
/*
|
||||
* We're not deleting all events, so we must resubmit the
|
||||
* event that we are still interested in if one exists.
|
||||
*/
|
||||
|
||||
if ((events & POLLIN) && evdp->evwrite != NULL) {
|
||||
/* Deleting read, still care about write */
|
||||
devpoll_queue(devpollop, fd, POLLOUT);
|
||||
needwritedelete = 0;
|
||||
} else if ((events & POLLOUT) && evdp->evread != NULL) {
|
||||
/* Deleting write, still care about read */
|
||||
devpoll_queue(devpollop, fd, POLLIN);
|
||||
needreaddelete = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (needreaddelete)
|
||||
evdp->evread = NULL;
|
||||
if (needwritedelete)
|
||||
evdp->evwrite = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
devpoll_dealloc(struct event_base *base, void *arg)
|
||||
{
|
||||
struct devpollop *devpollop = arg;
|
||||
|
||||
evsignal_dealloc(base);
|
||||
if (devpollop->fds)
|
||||
free(devpollop->fds);
|
||||
if (devpollop->events)
|
||||
free(devpollop->events);
|
||||
if (devpollop->changes)
|
||||
free(devpollop->changes);
|
||||
if (devpollop->dpfd >= 0)
|
||||
close(devpollop->dpfd);
|
||||
|
||||
memset(devpollop, 0, sizeof(struct devpollop));
|
||||
free(devpollop);
|
||||
}
|
||||
|
||||
#endif /* HAVE_DEVPOLL */
|
||||
360
extra/libevent/epoll.c
Normal file
360
extra/libevent/epoll.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "evsignal.h"
|
||||
#include "log.h"
|
||||
|
||||
/* due to limitations in the epoll interface, we need to keep track of
|
||||
* all file descriptors outself.
|
||||
*/
|
||||
struct evepoll {
|
||||
struct event *evread;
|
||||
struct event *evwrite;
|
||||
};
|
||||
|
||||
struct epollop {
|
||||
struct evepoll *fds;
|
||||
int nfds;
|
||||
struct epoll_event *events;
|
||||
int nevents;
|
||||
int epfd;
|
||||
};
|
||||
|
||||
static void *epoll_init (struct event_base *);
|
||||
static int epoll_add (void *, struct event *);
|
||||
static int epoll_del (void *, struct event *);
|
||||
static int epoll_dispatch (struct event_base *, void *, struct timeval *);
|
||||
static void epoll_dealloc (struct event_base *, void *);
|
||||
|
||||
struct eventop epollops = {
|
||||
"epoll",
|
||||
epoll_init,
|
||||
epoll_add,
|
||||
epoll_del,
|
||||
epoll_dispatch,
|
||||
epoll_dealloc,
|
||||
1 /* need reinit */
|
||||
};
|
||||
|
||||
#ifdef HAVE_SETFD
|
||||
#define FD_CLOSEONEXEC(x) do { \
|
||||
if (fcntl(x, F_SETFD, 1) == -1) \
|
||||
event_warn("fcntl(%d, F_SETFD)", x); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FD_CLOSEONEXEC(x)
|
||||
#endif
|
||||
|
||||
#define NEVENT 32000
|
||||
|
||||
static void *
|
||||
epoll_init(struct event_base *base)
|
||||
{
|
||||
int epfd, nfiles = NEVENT;
|
||||
struct rlimit rl;
|
||||
struct epollop *epollop;
|
||||
|
||||
/* Disable epollueue when this environment variable is set */
|
||||
if (getenv("EVENT_NOEPOLL"))
|
||||
return (NULL);
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
|
||||
rl.rlim_cur != RLIM_INFINITY) {
|
||||
/*
|
||||
* Solaris is somewhat retarded - it's important to drop
|
||||
* backwards compatibility when making changes. So, don't
|
||||
* dare to put rl.rlim_cur here.
|
||||
*/
|
||||
nfiles = rl.rlim_cur - 1;
|
||||
}
|
||||
|
||||
/* Initalize the kernel queue */
|
||||
|
||||
if ((epfd = epoll_create(nfiles)) == -1) {
|
||||
event_warn("epoll_create");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
FD_CLOSEONEXEC(epfd);
|
||||
|
||||
if (!(epollop = calloc(1, sizeof(struct epollop))))
|
||||
return (NULL);
|
||||
|
||||
epollop->epfd = epfd;
|
||||
|
||||
/* Initalize fields */
|
||||
epollop->events = malloc(nfiles * sizeof(struct epoll_event));
|
||||
if (epollop->events == NULL) {
|
||||
free(epollop);
|
||||
return (NULL);
|
||||
}
|
||||
epollop->nevents = nfiles;
|
||||
|
||||
epollop->fds = calloc(nfiles, sizeof(struct evepoll));
|
||||
if (epollop->fds == NULL) {
|
||||
free(epollop->events);
|
||||
free(epollop);
|
||||
return (NULL);
|
||||
}
|
||||
epollop->nfds = nfiles;
|
||||
|
||||
evsignal_init(base);
|
||||
|
||||
return (epollop);
|
||||
}
|
||||
|
||||
static int
|
||||
epoll_recalc(struct event_base *base __attribute__((unused)),
|
||||
void *arg, int max)
|
||||
{
|
||||
struct epollop *epollop = arg;
|
||||
|
||||
if (max > epollop->nfds) {
|
||||
struct evepoll *fds;
|
||||
int nfds;
|
||||
|
||||
nfds = epollop->nfds;
|
||||
while (nfds < max)
|
||||
nfds <<= 1;
|
||||
|
||||
fds = realloc(epollop->fds, nfds * sizeof(struct evepoll));
|
||||
if (fds == NULL) {
|
||||
event_warn("realloc");
|
||||
return (-1);
|
||||
}
|
||||
epollop->fds = fds;
|
||||
memset(fds + epollop->nfds, 0,
|
||||
(nfds - epollop->nfds) * sizeof(struct evepoll));
|
||||
epollop->nfds = nfds;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
|
||||
{
|
||||
struct epollop *epollop = arg;
|
||||
struct epoll_event *events = epollop->events;
|
||||
struct evepoll *evep;
|
||||
int i, res, timeout = -1;
|
||||
|
||||
if (tv != NULL)
|
||||
timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
|
||||
|
||||
res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
|
||||
|
||||
if (res == -1) {
|
||||
if (errno != EINTR) {
|
||||
event_warn("epoll_wait");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
evsignal_process(base);
|
||||
return (0);
|
||||
} else if (base->sig.evsignal_caught) {
|
||||
evsignal_process(base);
|
||||
}
|
||||
|
||||
event_debug(("%s: epoll_wait reports %d", __func__, res));
|
||||
|
||||
for (i = 0; i < res; i++) {
|
||||
int what = events[i].events;
|
||||
struct event *evread = NULL, *evwrite = NULL;
|
||||
|
||||
evep = (struct evepoll *)events[i].data.ptr;
|
||||
|
||||
if (what & (EPOLLHUP|EPOLLERR)) {
|
||||
evread = evep->evread;
|
||||
evwrite = evep->evwrite;
|
||||
} else {
|
||||
if (what & EPOLLIN) {
|
||||
evread = evep->evread;
|
||||
}
|
||||
|
||||
if (what & EPOLLOUT) {
|
||||
evwrite = evep->evwrite;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(evread||evwrite))
|
||||
continue;
|
||||
|
||||
if (evread != NULL)
|
||||
event_active(evread, EV_READ, 1);
|
||||
if (evwrite != NULL)
|
||||
event_active(evwrite, EV_WRITE, 1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
epoll_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct epollop *epollop = arg;
|
||||
struct epoll_event epev = {0, {0}};
|
||||
struct evepoll *evep;
|
||||
int fd, op, events;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_add(ev));
|
||||
|
||||
fd = ev->ev_fd;
|
||||
if (fd >= epollop->nfds) {
|
||||
/* Extent the file descriptor array as necessary */
|
||||
if (epoll_recalc(ev->ev_base, epollop, fd) == -1)
|
||||
return (-1);
|
||||
}
|
||||
evep = &epollop->fds[fd];
|
||||
op = EPOLL_CTL_ADD;
|
||||
events = 0;
|
||||
if (evep->evread != NULL) {
|
||||
events |= EPOLLIN;
|
||||
op = EPOLL_CTL_MOD;
|
||||
}
|
||||
if (evep->evwrite != NULL) {
|
||||
events |= EPOLLOUT;
|
||||
op = EPOLL_CTL_MOD;
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_READ)
|
||||
events |= EPOLLIN;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
events |= EPOLLOUT;
|
||||
|
||||
epev.data.ptr = evep;
|
||||
epev.events = events;
|
||||
if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
|
||||
return (-1);
|
||||
|
||||
/* Update events responsible */
|
||||
if (ev->ev_events & EV_READ)
|
||||
evep->evread = ev;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
evep->evwrite = ev;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
epoll_del(void *arg, struct event *ev)
|
||||
{
|
||||
struct epollop *epollop = arg;
|
||||
struct epoll_event epev = {0, {0}};
|
||||
struct evepoll *evep;
|
||||
int fd, events, op;
|
||||
int needwritedelete = 1, needreaddelete = 1;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_del(ev));
|
||||
|
||||
fd = ev->ev_fd;
|
||||
if (fd >= epollop->nfds)
|
||||
return (0);
|
||||
evep = &epollop->fds[fd];
|
||||
|
||||
op = EPOLL_CTL_DEL;
|
||||
events = 0;
|
||||
|
||||
if (ev->ev_events & EV_READ)
|
||||
events |= EPOLLIN;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
events |= EPOLLOUT;
|
||||
|
||||
if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) {
|
||||
if ((events & EPOLLIN) && evep->evwrite != NULL) {
|
||||
needwritedelete = 0;
|
||||
events = EPOLLOUT;
|
||||
op = EPOLL_CTL_MOD;
|
||||
} else if ((events & EPOLLOUT) && evep->evread != NULL) {
|
||||
needreaddelete = 0;
|
||||
events = EPOLLIN;
|
||||
op = EPOLL_CTL_MOD;
|
||||
}
|
||||
}
|
||||
|
||||
epev.events = events;
|
||||
epev.data.ptr = evep;
|
||||
|
||||
if (needreaddelete)
|
||||
evep->evread = NULL;
|
||||
if (needwritedelete)
|
||||
evep->evwrite = NULL;
|
||||
|
||||
if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
epoll_dealloc(struct event_base *base, void *arg)
|
||||
{
|
||||
struct epollop *epollop = arg;
|
||||
|
||||
evsignal_dealloc(base);
|
||||
if (epollop->fds)
|
||||
free(epollop->fds);
|
||||
if (epollop->events)
|
||||
free(epollop->events);
|
||||
if (epollop->epfd >= 0)
|
||||
close(epollop->epfd);
|
||||
|
||||
memset(epollop, 0, sizeof(struct epollop));
|
||||
free(epollop);
|
||||
}
|
||||
|
||||
#endif /* HAVE_EPOLL */
|
||||
60
extra/libevent/epoll_sub.c
Normal file
60
extra/libevent/epoll_sub.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2003 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
epoll_create(int size)
|
||||
{
|
||||
return (syscall(__NR_epoll_create, size));
|
||||
}
|
||||
|
||||
int
|
||||
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
|
||||
{
|
||||
|
||||
return (syscall(__NR_epoll_ctl, epfd, op, fd, event));
|
||||
}
|
||||
|
||||
int
|
||||
epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
|
||||
{
|
||||
return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout));
|
||||
}
|
||||
|
||||
#endif /* HAVE_EPOLL */
|
||||
418
extra/libevent/evbuffer.c
Normal file
418
extra/libevent/evbuffer.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include "evutil.h"
|
||||
#include "event.h"
|
||||
|
||||
/* prototypes */
|
||||
|
||||
void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t);
|
||||
void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
|
||||
|
||||
static int
|
||||
bufferevent_add(struct event *ev, int timeout)
|
||||
{
|
||||
struct timeval tv, *ptv = NULL;
|
||||
|
||||
if (timeout) {
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = timeout;
|
||||
ptv = &tv;
|
||||
}
|
||||
|
||||
return (event_add(ev, ptv));
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is executed when the size of the input buffer changes.
|
||||
* We use it to apply back pressure on the reading side.
|
||||
*/
|
||||
|
||||
void
|
||||
bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old __attribute__((unused)), size_t now,
|
||||
void *arg) {
|
||||
struct bufferevent *bufev = arg;
|
||||
/*
|
||||
* If we are below the watermark then reschedule reading if it's
|
||||
* still enabled.
|
||||
*/
|
||||
if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
|
||||
evbuffer_setcb(buf, NULL, NULL);
|
||||
|
||||
if (bufev->enabled & EV_READ)
|
||||
bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bufferevent_readcb(int fd, short event, void *arg)
|
||||
{
|
||||
struct bufferevent *bufev = arg;
|
||||
int res = 0;
|
||||
short what = EVBUFFER_READ;
|
||||
size_t len;
|
||||
int howmuch = -1;
|
||||
|
||||
if (event == EV_TIMEOUT) {
|
||||
what |= EVBUFFER_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a high watermark configured then we don't want to
|
||||
* read more data than would make us reach the watermark.
|
||||
*/
|
||||
if (bufev->wm_read.high != 0)
|
||||
howmuch = (int)bufev->wm_read.high;
|
||||
|
||||
res = evbuffer_read(bufev->input, fd, howmuch);
|
||||
if (res == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
goto reschedule;
|
||||
/* error case */
|
||||
what |= EVBUFFER_ERROR;
|
||||
} else if (res == 0) {
|
||||
/* eof case */
|
||||
what |= EVBUFFER_EOF;
|
||||
}
|
||||
|
||||
if (res <= 0)
|
||||
goto error;
|
||||
|
||||
bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
||||
|
||||
/* See if this callbacks meets the water marks */
|
||||
len = EVBUFFER_LENGTH(bufev->input);
|
||||
if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
|
||||
return;
|
||||
if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
|
||||
struct evbuffer *buf = bufev->input;
|
||||
event_del(&bufev->ev_read);
|
||||
|
||||
/* Now schedule a callback for us */
|
||||
evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Invoke the user callback - must always be called last */
|
||||
if (bufev->readcb != NULL)
|
||||
(*bufev->readcb)(bufev, bufev->cbarg);
|
||||
return;
|
||||
|
||||
reschedule:
|
||||
bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
||||
return;
|
||||
|
||||
error:
|
||||
(*bufev->errorcb)(bufev, what, bufev->cbarg);
|
||||
}
|
||||
|
||||
static void
|
||||
bufferevent_writecb(int fd, short event, void *arg)
|
||||
{
|
||||
struct bufferevent *bufev = arg;
|
||||
int res = 0;
|
||||
short what = EVBUFFER_WRITE;
|
||||
|
||||
if (event == EV_TIMEOUT) {
|
||||
what |= EVBUFFER_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVBUFFER_LENGTH(bufev->output)) {
|
||||
res = evbuffer_write(bufev->output, fd);
|
||||
if (res == -1) {
|
||||
#ifndef WIN32
|
||||
/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
|
||||
*set errno. thus this error checking is not portable*/
|
||||
if (errno == EAGAIN ||
|
||||
errno == EINTR ||
|
||||
errno == EINPROGRESS)
|
||||
goto reschedule;
|
||||
/* error case */
|
||||
what |= EVBUFFER_ERROR;
|
||||
|
||||
#else
|
||||
goto reschedule;
|
||||
#endif
|
||||
|
||||
} else if (res == 0) {
|
||||
/* eof case */
|
||||
what |= EVBUFFER_EOF;
|
||||
}
|
||||
if (res <= 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVBUFFER_LENGTH(bufev->output) != 0)
|
||||
bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
||||
|
||||
/*
|
||||
* Invoke the user callback if our buffer is drained or below the
|
||||
* low watermark.
|
||||
*/
|
||||
if (bufev->writecb != NULL &&
|
||||
EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
|
||||
(*bufev->writecb)(bufev, bufev->cbarg);
|
||||
|
||||
return;
|
||||
|
||||
reschedule:
|
||||
if (EVBUFFER_LENGTH(bufev->output) != 0)
|
||||
bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
||||
return;
|
||||
|
||||
error:
|
||||
(*bufev->errorcb)(bufev, what, bufev->cbarg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new buffered event object.
|
||||
*
|
||||
* The read callback is invoked whenever we read new data.
|
||||
* The write callback is invoked whenever the output buffer is drained.
|
||||
* The error callback is invoked on a write/read error or on EOF.
|
||||
*
|
||||
* Both read and write callbacks maybe NULL. The error callback is not
|
||||
* allowed to be NULL and have to be provided always.
|
||||
*/
|
||||
|
||||
struct bufferevent *
|
||||
bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
|
||||
everrorcb errorcb, void *cbarg)
|
||||
{
|
||||
struct bufferevent *bufev;
|
||||
|
||||
if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if ((bufev->input = evbuffer_new()) == NULL) {
|
||||
free(bufev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((bufev->output = evbuffer_new()) == NULL) {
|
||||
evbuffer_free(bufev->input);
|
||||
free(bufev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
|
||||
event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
|
||||
|
||||
bufev->readcb = readcb;
|
||||
bufev->writecb = writecb;
|
||||
bufev->errorcb = errorcb;
|
||||
|
||||
bufev->cbarg = cbarg;
|
||||
|
||||
/*
|
||||
* Set to EV_WRITE so that using bufferevent_write is going to
|
||||
* trigger a callback. Reading needs to be explicitly enabled
|
||||
* because otherwise no data will be available.
|
||||
*/
|
||||
bufev->enabled = EV_WRITE;
|
||||
|
||||
return (bufev);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_priority_set(struct bufferevent *bufev, int priority)
|
||||
{
|
||||
if (event_priority_set(&bufev->ev_read, priority) == -1)
|
||||
return (-1);
|
||||
if (event_priority_set(&bufev->ev_write, priority) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Closing the file descriptor is the responsibility of the caller */
|
||||
|
||||
void
|
||||
bufferevent_free(struct bufferevent *bufev)
|
||||
{
|
||||
event_del(&bufev->ev_read);
|
||||
event_del(&bufev->ev_write);
|
||||
|
||||
evbuffer_free(bufev->input);
|
||||
evbuffer_free(bufev->output);
|
||||
|
||||
free(bufev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 on success;
|
||||
* -1 on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = evbuffer_add(bufev->output, data, size);
|
||||
|
||||
if (res == -1)
|
||||
return (res);
|
||||
|
||||
/* If everything is okay, we need to schedule a write */
|
||||
if (size > 0 && (bufev->enabled & EV_WRITE))
|
||||
bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = bufferevent_write(bufev, buf->buffer, buf->off);
|
||||
if (res != -1)
|
||||
evbuffer_drain(buf, buf->off);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
size_t
|
||||
bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
|
||||
{
|
||||
struct evbuffer *buf = bufev->input;
|
||||
|
||||
if (buf->off < size)
|
||||
size = buf->off;
|
||||
|
||||
/* Copy the available data to the user buffer */
|
||||
memcpy(data, buf->buffer, size);
|
||||
|
||||
if (size)
|
||||
evbuffer_drain(buf, size);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_enable(struct bufferevent *bufev, short event)
|
||||
{
|
||||
if (event & EV_READ) {
|
||||
if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
|
||||
return (-1);
|
||||
}
|
||||
if (event & EV_WRITE) {
|
||||
if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bufev->enabled |= event;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_disable(struct bufferevent *bufev, short event)
|
||||
{
|
||||
if (event & EV_READ) {
|
||||
if (event_del(&bufev->ev_read) == -1)
|
||||
return (-1);
|
||||
}
|
||||
if (event & EV_WRITE) {
|
||||
if (event_del(&bufev->ev_write) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bufev->enabled &= ~event;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the read and write timeout for a buffered event.
|
||||
*/
|
||||
|
||||
void
|
||||
bufferevent_settimeout(struct bufferevent *bufev,
|
||||
int timeout_read, int timeout_write) {
|
||||
bufev->timeout_read = timeout_read;
|
||||
bufev->timeout_write = timeout_write;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the water marks
|
||||
*/
|
||||
|
||||
void
|
||||
bufferevent_setwatermark(struct bufferevent *bufev, short events,
|
||||
size_t lowmark, size_t highmark)
|
||||
{
|
||||
if (events & EV_READ) {
|
||||
bufev->wm_read.low = lowmark;
|
||||
bufev->wm_read.high = highmark;
|
||||
}
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
bufev->wm_write.low = lowmark;
|
||||
bufev->wm_write.high = highmark;
|
||||
}
|
||||
|
||||
/* If the watermarks changed then see if we should call read again */
|
||||
bufferevent_read_pressure_cb(bufev->input,
|
||||
0, EVBUFFER_LENGTH(bufev->input), bufev);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = event_base_set(base, &bufev->ev_read);
|
||||
if (res == -1)
|
||||
return (res);
|
||||
|
||||
res = event_base_set(base, &bufev->ev_write);
|
||||
return (res);
|
||||
}
|
||||
3150
extra/libevent/evdns.c
Normal file
3150
extra/libevent/evdns.c
Normal file
File diff suppressed because it is too large
Load Diff
528
extra/libevent/evdns.h
Normal file
528
extra/libevent/evdns.h
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The original DNS code is due to Adam Langley with heavy
|
||||
* modifications by Nick Mathewson. Adam put his DNS software in the
|
||||
* public domain. You can find his original copyright below. Please,
|
||||
* aware that the code as part of libevent is governed by the 3-clause
|
||||
* BSD license above.
|
||||
*
|
||||
* This software is Public Domain. To view a copy of the public domain dedication,
|
||||
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
|
||||
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
|
||||
*
|
||||
* I ask and expect, but do not require, that all derivative works contain an
|
||||
* attribution similar to:
|
||||
* Parts developed by Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* You may wish to replace the word "Parts" with something else depending on
|
||||
* the amount of original code.
|
||||
*
|
||||
* (Derivative works does not include programs which link against, run or include
|
||||
* the source verbatim in their source distributions)
|
||||
*/
|
||||
|
||||
/** @file evdns.h
|
||||
*
|
||||
* Welcome, gentle reader
|
||||
*
|
||||
* Async DNS lookups are really a whole lot harder than they should be,
|
||||
* mostly stemming from the fact that the libc resolver has never been
|
||||
* very good at them. Before you use this library you should see if libc
|
||||
* can do the job for you with the modern async call getaddrinfo_a
|
||||
* (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
|
||||
* please continue.
|
||||
*
|
||||
* This code is based on libevent and you must call event_init before
|
||||
* any of the APIs in this file. You must also seed the OpenSSL random
|
||||
* source if you are using OpenSSL for ids (see below).
|
||||
*
|
||||
* This library is designed to be included and shipped with your source
|
||||
* code. You statically link with it. You should also test for the
|
||||
* existence of strtok_r and define HAVE_STRTOK_R if you have it.
|
||||
*
|
||||
* The DNS protocol requires a good source of id numbers and these
|
||||
* numbers should be unpredictable for spoofing reasons. There are
|
||||
* three methods for generating them here and you must define exactly
|
||||
* one of them. In increasing order of preference:
|
||||
*
|
||||
* DNS_USE_GETTIMEOFDAY_FOR_ID:
|
||||
* Using the bottom 16 bits of the usec result from gettimeofday. This
|
||||
* is a pretty poor solution but should work anywhere.
|
||||
* DNS_USE_CPU_CLOCK_FOR_ID:
|
||||
* Using the bottom 16 bits of the nsec result from the CPU's time
|
||||
* counter. This is better, but may not work everywhere. Requires
|
||||
* POSIX realtime support and you'll need to link against -lrt on
|
||||
* glibc systems at least.
|
||||
* DNS_USE_OPENSSL_FOR_ID:
|
||||
* Uses the OpenSSL RAND_bytes call to generate the data. You must
|
||||
* have seeded the pool before making any calls to this library.
|
||||
*
|
||||
* The library keeps track of the state of nameservers and will avoid
|
||||
* them when they go down. Otherwise it will round robin between them.
|
||||
*
|
||||
* Quick start guide:
|
||||
* #include "evdns.h"
|
||||
* void callback(int result, char type, int count, int ttl,
|
||||
* void *addresses, void *arg);
|
||||
* evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
|
||||
* evdns_resolve("www.hostname.com", 0, callback, NULL);
|
||||
*
|
||||
* When the lookup is complete the callback function is called. The
|
||||
* first argument will be one of the DNS_ERR_* defines in evdns.h.
|
||||
* Hopefully it will be DNS_ERR_NONE, in which case type will be
|
||||
* DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
|
||||
* which the data can be cached for (in seconds), addresses will point
|
||||
* to an array of uint32_t's and arg will be whatever you passed to
|
||||
* evdns_resolve.
|
||||
*
|
||||
* Searching:
|
||||
*
|
||||
* In order for this library to be a good replacement for glibc's resolver it
|
||||
* supports searching. This involves setting a list of default domains, in
|
||||
* which names will be queried for. The number of dots in the query name
|
||||
* determines the order in which this list is used.
|
||||
*
|
||||
* Searching appears to be a single lookup from the point of view of the API,
|
||||
* although many DNS queries may be generated from a single call to
|
||||
* evdns_resolve. Searching can also drastically slow down the resolution
|
||||
* of names.
|
||||
*
|
||||
* To disable searching:
|
||||
* 1. Never set it up. If you never call evdns_resolv_conf_parse or
|
||||
* evdns_search_add then no searching will occur.
|
||||
*
|
||||
* 2. If you do call evdns_resolv_conf_parse then don't pass
|
||||
* DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
|
||||
*
|
||||
* 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
|
||||
*
|
||||
* The order of searches depends on the number of dots in the name. If the
|
||||
* number is greater than the ndots setting then the names is first tried
|
||||
* globally. Otherwise each search domain is appended in turn.
|
||||
*
|
||||
* The ndots setting can either be set from a resolv.conf, or by calling
|
||||
* evdns_search_ndots_set.
|
||||
*
|
||||
* For example, with ndots set to 1 (the default) and a search domain list of
|
||||
* ["myhome.net"]:
|
||||
* Query: www
|
||||
* Order: www.myhome.net, www.
|
||||
*
|
||||
* Query: www.abc
|
||||
* Order: www.abc., www.abc.myhome.net
|
||||
*
|
||||
* Internals:
|
||||
*
|
||||
* Requests are kept in two queues. The first is the inflight queue. In
|
||||
* this queue requests have an allocated transaction id and nameserver.
|
||||
* They will soon be transmitted if they haven't already been.
|
||||
*
|
||||
* The second is the waiting queue. The size of the inflight ring is
|
||||
* limited and all other requests wait in waiting queue for space. This
|
||||
* bounds the number of concurrent requests so that we don't flood the
|
||||
* nameserver. Several algorithms require a full walk of the inflight
|
||||
* queue and so bounding its size keeps thing going nicely under huge
|
||||
* (many thousands of requests) loads.
|
||||
*
|
||||
* If a nameserver loses too many requests it is considered down and we
|
||||
* try not to use it. After a while we send a probe to that nameserver
|
||||
* (a lookup for google.com) and, if it replies, we consider it working
|
||||
* again. If the nameserver fails a probe we wait longer to try again
|
||||
* with the next probe.
|
||||
*/
|
||||
|
||||
#ifndef EVENTDNS_H
|
||||
#define EVENTDNS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For integer types. */
|
||||
#include <evutil.h>
|
||||
|
||||
/** Error codes 0-5 are as described in RFC 1035. */
|
||||
#define DNS_ERR_NONE 0
|
||||
/** The name server was unable to interpret the query */
|
||||
#define DNS_ERR_FORMAT 1
|
||||
/** The name server was unable to process this query due to a problem with the
|
||||
* name server */
|
||||
#define DNS_ERR_SERVERFAILED 2
|
||||
/** The domain name does not exist */
|
||||
#define DNS_ERR_NOTEXIST 3
|
||||
/** The name server does not support the requested kind of query */
|
||||
#define DNS_ERR_NOTIMPL 4
|
||||
/** The name server refuses to reform the specified operation for policy
|
||||
* reasons */
|
||||
#define DNS_ERR_REFUSED 5
|
||||
/** The reply was truncated or ill-formated */
|
||||
#define DNS_ERR_TRUNCATED 65
|
||||
/** An unknown error occurred */
|
||||
#define DNS_ERR_UNKNOWN 66
|
||||
/** Communication with the server timed out */
|
||||
#define DNS_ERR_TIMEOUT 67
|
||||
/** The request was canceled because the DNS subsystem was shut down. */
|
||||
#define DNS_ERR_SHUTDOWN 68
|
||||
|
||||
#define DNS_IPv4_A 1
|
||||
#define DNS_PTR 2
|
||||
#define DNS_IPv6_AAAA 3
|
||||
|
||||
#define DNS_QUERY_NO_SEARCH 1
|
||||
|
||||
#define DNS_OPTION_SEARCH 1
|
||||
#define DNS_OPTION_NAMESERVERS 2
|
||||
#define DNS_OPTION_MISC 4
|
||||
#define DNS_OPTIONS_ALL 7
|
||||
|
||||
/**
|
||||
* The callback that contains the results from a lookup.
|
||||
* - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
|
||||
* - count contains the number of addresses of form type
|
||||
* - ttl is the number of seconds the resolution may be cached for.
|
||||
* - addresses needs to be cast according to type
|
||||
*/
|
||||
typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
|
||||
|
||||
/**
|
||||
Initialize the asynchronous DNS library.
|
||||
|
||||
This function initializes support for non-blocking name resolution by
|
||||
calling evdns_resolv_conf_parse() on UNIX and
|
||||
evdns_config_windows_nameservers() on Windows.
|
||||
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_shutdown()
|
||||
*/
|
||||
int evdns_init(void);
|
||||
|
||||
|
||||
/**
|
||||
Shut down the asynchronous DNS resolver and terminate all active requests.
|
||||
|
||||
If the 'fail_requests' option is enabled, all active requests will return
|
||||
an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
|
||||
the requests will be silently discarded.
|
||||
|
||||
@param fail_requests if zero, active requests will be aborted; if non-zero,
|
||||
active requests will return DNS_ERR_SHUTDOWN.
|
||||
@see evdns_init()
|
||||
*/
|
||||
void evdns_shutdown(int fail_requests);
|
||||
|
||||
|
||||
/**
|
||||
Convert a DNS error code to a string.
|
||||
|
||||
@param err the DNS error code
|
||||
@return a string containing an explanation of the error code
|
||||
*/
|
||||
const char *evdns_err_to_string(int err);
|
||||
|
||||
|
||||
/**
|
||||
Add a nameserver.
|
||||
|
||||
The address should be an IPv4 address in network byte order.
|
||||
The type of address is chosen so that it matches in_addr.s_addr.
|
||||
|
||||
@param address an IP address in network byte order
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_nameserver_ip_add()
|
||||
*/
|
||||
int evdns_nameserver_add(unsigned long int address);
|
||||
|
||||
|
||||
/**
|
||||
Get the number of configured nameservers.
|
||||
|
||||
This returns the number of configured nameservers (not necessarily the
|
||||
number of running nameservers). This is useful for double-checking
|
||||
whether our calls to the various nameserver configuration functions
|
||||
have been successful.
|
||||
|
||||
@return the number of configured nameservers
|
||||
@see evdns_nameserver_add()
|
||||
*/
|
||||
int evdns_count_nameservers(void);
|
||||
|
||||
|
||||
/**
|
||||
Remove all configured nameservers, and suspend all pending resolves.
|
||||
|
||||
Resolves will not necessarily be re-attempted until evdns_resume() is called.
|
||||
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_resume()
|
||||
*/
|
||||
int evdns_clear_nameservers_and_suspend(void);
|
||||
|
||||
|
||||
/**
|
||||
Resume normal operation and continue any suspended resolve requests.
|
||||
|
||||
Re-attempt resolves left in limbo after an earlier call to
|
||||
evdns_clear_nameservers_and_suspend().
|
||||
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_clear_nameservers_and_suspend()
|
||||
*/
|
||||
int evdns_resume(void);
|
||||
|
||||
|
||||
/**
|
||||
Add a nameserver.
|
||||
|
||||
This wraps the evdns_nameserver_add() function by parsing a string as an IP
|
||||
address and adds it as a nameserver.
|
||||
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_nameserver_add()
|
||||
*/
|
||||
int evdns_nameserver_ip_add(const char *ip_as_string);
|
||||
|
||||
|
||||
/**
|
||||
Lookup an A record for a given name.
|
||||
|
||||
@param name a DNS hostname
|
||||
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
|
||||
@param callback a callback function to invoke when the request is completed
|
||||
@param ptr an argument to pass to the callback function
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
|
||||
*/
|
||||
int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
|
||||
|
||||
|
||||
/**
|
||||
Lookup an AAAA record for a given name.
|
||||
|
||||
@param name a DNS hostname
|
||||
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
|
||||
@param callback a callback function to invoke when the request is completed
|
||||
@param ptr an argument to pass to the callback function
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
|
||||
*/
|
||||
int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
|
||||
|
||||
struct in_addr;
|
||||
struct in6_addr;
|
||||
|
||||
/**
|
||||
Lookup a PTR record for a given IP address.
|
||||
|
||||
@param in an IPv4 address
|
||||
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
|
||||
@param callback a callback function to invoke when the request is completed
|
||||
@param ptr an argument to pass to the callback function
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_resolve_reverse_ipv6()
|
||||
*/
|
||||
int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
|
||||
|
||||
|
||||
/**
|
||||
Lookup a PTR record for a given IPv6 address.
|
||||
|
||||
@param in an IPv6 address
|
||||
@param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
|
||||
@param callback a callback function to invoke when the request is completed
|
||||
@param ptr an argument to pass to the callback function
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_resolve_reverse_ipv6()
|
||||
*/
|
||||
int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
|
||||
|
||||
|
||||
/**
|
||||
Set the value of a configuration option.
|
||||
|
||||
The currently available configuration options are:
|
||||
|
||||
ndots, timeout, max-timeouts, max-inflight, and attempts
|
||||
|
||||
@param option the name of the configuration option to be modified
|
||||
@param val the value to be set
|
||||
@param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int evdns_set_option(const char *option, const char *val, int flags);
|
||||
|
||||
|
||||
/**
|
||||
Parse a resolv.conf file.
|
||||
|
||||
The 'flags' parameter determines what information is parsed from the
|
||||
resolv.conf file. See the man page for resolv.conf for the format of this
|
||||
file.
|
||||
|
||||
The following directives are not parsed from the file: sortlist, rotate,
|
||||
no-check-names, inet6, debug.
|
||||
|
||||
If this function encounters an error, the possible return values are: 1 =
|
||||
failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
|
||||
memory, 5 = short read from file, 6 = no nameservers listed in the file
|
||||
|
||||
@param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
|
||||
DNS_OPTIONS_ALL
|
||||
@param filename the path to the resolv.conf file
|
||||
@return 0 if successful, or various positive error codes if an error
|
||||
occurred (see above)
|
||||
@see resolv.conf(3), evdns_config_windows_nameservers()
|
||||
*/
|
||||
int evdns_resolv_conf_parse(int flags, const char *const filename);
|
||||
|
||||
|
||||
/**
|
||||
Obtain nameserver information using the Windows API.
|
||||
|
||||
Attempt to configure a set of nameservers based on platform settings on
|
||||
a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
|
||||
looks in the registry.
|
||||
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
@see evdns_resolv_conf_parse()
|
||||
*/
|
||||
#ifdef MS_WINDOWS
|
||||
int evdns_config_windows_nameservers(void);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
Clear the list of search domains.
|
||||
*/
|
||||
void evdns_search_clear(void);
|
||||
|
||||
|
||||
/**
|
||||
Add a domain to the list of search domains
|
||||
|
||||
@param domain the domain to be added to the search list
|
||||
*/
|
||||
void evdns_search_add(const char *domain);
|
||||
|
||||
|
||||
/**
|
||||
Set the 'ndots' parameter for searches.
|
||||
|
||||
Sets the number of dots which, when found in a name, causes
|
||||
the first query to be without any search domain.
|
||||
|
||||
@param ndots the new ndots parameter
|
||||
*/
|
||||
void evdns_search_ndots_set(const int ndots);
|
||||
|
||||
/**
|
||||
A callback that is invoked when a log message is generated
|
||||
|
||||
@param is_warning indicates if the log message is a 'warning'
|
||||
@param msg the content of the log message
|
||||
*/
|
||||
typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
|
||||
|
||||
|
||||
/**
|
||||
Set the callback function to handle log messages.
|
||||
|
||||
@param fn the callback to be invoked when a log message is generated
|
||||
*/
|
||||
void evdns_set_log_fn(evdns_debug_log_fn_type fn);
|
||||
|
||||
/**
|
||||
Set a callback that will be invoked to generate transaction IDs. By
|
||||
default, we pick transaction IDs based on the current clock time.
|
||||
|
||||
@param fn the new callback, or NULL to use the default.
|
||||
*/
|
||||
void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
|
||||
|
||||
#define DNS_NO_SEARCH 1
|
||||
|
||||
/*
|
||||
* Structures and functions used to implement a DNS server.
|
||||
*/
|
||||
|
||||
struct evdns_server_request {
|
||||
int flags;
|
||||
int nquestions;
|
||||
struct evdns_server_question **questions;
|
||||
};
|
||||
struct evdns_server_question {
|
||||
int type;
|
||||
#ifdef __cplusplus
|
||||
int dns_question_class;
|
||||
#else
|
||||
/* You should refer to this field as "dns_question_class". The
|
||||
* name "class" works in C for backward compatibility, and will be
|
||||
* removed in a future version. (1.5 or later). */
|
||||
int class;
|
||||
#define dns_question_class class
|
||||
#endif
|
||||
char name[1];
|
||||
};
|
||||
typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
|
||||
#define EVDNS_ANSWER_SECTION 0
|
||||
#define EVDNS_AUTHORITY_SECTION 1
|
||||
#define EVDNS_ADDITIONAL_SECTION 2
|
||||
|
||||
#define EVDNS_TYPE_A 1
|
||||
#define EVDNS_TYPE_NS 2
|
||||
#define EVDNS_TYPE_CNAME 5
|
||||
#define EVDNS_TYPE_SOA 6
|
||||
#define EVDNS_TYPE_PTR 12
|
||||
#define EVDNS_TYPE_MX 15
|
||||
#define EVDNS_TYPE_TXT 16
|
||||
#define EVDNS_TYPE_AAAA 28
|
||||
|
||||
#define EVDNS_QTYPE_AXFR 252
|
||||
#define EVDNS_QTYPE_ALL 255
|
||||
|
||||
#define EVDNS_CLASS_INET 1
|
||||
|
||||
struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
|
||||
void evdns_close_server_port(struct evdns_server_port *port);
|
||||
|
||||
int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
|
||||
int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
|
||||
int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
|
||||
int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
|
||||
int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
|
||||
|
||||
int evdns_server_request_respond(struct evdns_server_request *req, int err);
|
||||
int evdns_server_request_drop(struct evdns_server_request *req);
|
||||
struct sockaddr;
|
||||
int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !EVENTDNS_H */
|
||||
103
extra/libevent/event-internal.h
Normal file
103
extra/libevent/event-internal.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVENT_INTERNAL_H_
|
||||
#define _EVENT_INTERNAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "min_heap.h"
|
||||
#include "evsignal.h"
|
||||
|
||||
struct eventop {
|
||||
const char *name;
|
||||
void *(*init)(struct event_base *);
|
||||
int (*add)(void *, struct event *);
|
||||
int (*del)(void *, struct event *);
|
||||
int (*dispatch)(struct event_base *, void *, struct timeval *);
|
||||
void (*dealloc)(struct event_base *, void *);
|
||||
/* set if we need to reinitialize the event base */
|
||||
int need_reinit;
|
||||
};
|
||||
|
||||
struct event_base {
|
||||
const struct eventop *evsel;
|
||||
void *evbase;
|
||||
int event_count; /* counts number of total events */
|
||||
int event_count_active; /* counts number of active events */
|
||||
|
||||
int event_gotterm; /* Set to terminate loop */
|
||||
int event_break; /* Set to terminate loop immediately */
|
||||
|
||||
/* active event management */
|
||||
struct event_list **activequeues;
|
||||
int nactivequeues;
|
||||
|
||||
/* signal handling info */
|
||||
struct evsignal_info sig;
|
||||
|
||||
struct event_list eventqueue;
|
||||
struct timeval event_tv;
|
||||
|
||||
struct min_heap timeheap;
|
||||
};
|
||||
|
||||
/* Internal use only: Functions that might be missing from <sys/queue.h> */
|
||||
/* These following macros are copied from BSD sys/queue.h
|
||||
Copyright (c) 1991, 1993, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
*/
|
||||
#ifndef TAILQ_EMPTY
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_END(head) NULL
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#endif /* TAILQ_EMPTY */
|
||||
#ifndef HAVE_TAILQFOREACH
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
#endif /* TAILQ_FOREACH */
|
||||
|
||||
int _evsignal_set_handler(struct event_base *base, int evsignal,
|
||||
void (*fn)(int));
|
||||
int _evsignal_restore_handler(struct event_base *base, int evsignal);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVENT_INTERNAL_H_ */
|
||||
989
extra/libevent/event.c
Normal file
989
extra/libevent/event.c
Normal file
@@ -0,0 +1,989 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include "misc.h"
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "evutil.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef HAVE_EVENT_PORTS
|
||||
extern const struct eventop evportops;
|
||||
#endif
|
||||
#ifdef HAVE_SELECT
|
||||
extern const struct eventop selectops;
|
||||
#endif
|
||||
#ifdef HAVE_POLL
|
||||
extern const struct eventop pollops;
|
||||
#endif
|
||||
#ifdef HAVE_EPOLL
|
||||
extern const struct eventop epollops;
|
||||
#endif
|
||||
#ifdef HAVE_WORKING_KQUEUE
|
||||
extern const struct eventop kqops;
|
||||
#endif
|
||||
#ifdef HAVE_DEVPOLL
|
||||
extern const struct eventop devpollops;
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
extern const struct eventop win32ops;
|
||||
#endif
|
||||
|
||||
/* In order of preference */
|
||||
const struct eventop *eventops[] = {
|
||||
#ifdef HAVE_EVENT_PORTS
|
||||
&evportops,
|
||||
#endif
|
||||
#ifdef HAVE_WORKING_KQUEUE
|
||||
&kqops,
|
||||
#endif
|
||||
#ifdef HAVE_EPOLL
|
||||
&epollops,
|
||||
#endif
|
||||
#ifdef HAVE_DEVPOLL
|
||||
&devpollops,
|
||||
#endif
|
||||
#ifdef HAVE_POLL
|
||||
&pollops,
|
||||
#endif
|
||||
#ifdef HAVE_SELECT
|
||||
&selectops,
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
&win32ops,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Global state */
|
||||
struct event_base *current_base = NULL;
|
||||
extern struct event_base *evsignal_base;
|
||||
static int use_monotonic;
|
||||
|
||||
/* Handle signals - This is a deprecated interface */
|
||||
int (*event_sigcb)(void); /* Signal callback when gotsig is set */
|
||||
volatile sig_atomic_t event_gotsig; /* Set in signal handler */
|
||||
|
||||
/* Prototypes */
|
||||
static void event_queue_insert(struct event_base *, struct event *, int);
|
||||
static void event_queue_remove(struct event_base *, struct event *, int);
|
||||
static int event_haveevents(struct event_base *);
|
||||
|
||||
static void event_process_active(struct event_base *);
|
||||
|
||||
static int timeout_next(struct event_base *, struct timeval **);
|
||||
static void timeout_process(struct event_base *);
|
||||
static void timeout_correct(struct event_base *, struct timeval *);
|
||||
|
||||
static void
|
||||
detect_monotonic(void)
|
||||
{
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
||||
use_monotonic = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
gettime(struct timeval *tp)
|
||||
{
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
|
||||
if (use_monotonic) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
|
||||
return (-1);
|
||||
|
||||
tp->tv_sec = ts.tv_sec;
|
||||
tp->tv_usec = ts.tv_nsec / 1000;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (gettimeofday(tp, NULL));
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
event_init(void)
|
||||
{
|
||||
struct event_base *base = event_base_new();
|
||||
|
||||
if (base != NULL)
|
||||
current_base = base;
|
||||
|
||||
return (base);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
event_base_new(void)
|
||||
{
|
||||
int i;
|
||||
struct event_base *base;
|
||||
|
||||
if ((base = calloc(1, sizeof(struct event_base))) == NULL)
|
||||
event_err(1, "%s: calloc", __func__);
|
||||
|
||||
event_sigcb = NULL;
|
||||
event_gotsig = 0;
|
||||
|
||||
detect_monotonic();
|
||||
gettime(&base->event_tv);
|
||||
|
||||
min_heap_ctor(&base->timeheap);
|
||||
TAILQ_INIT(&base->eventqueue);
|
||||
TAILQ_INIT(&base->sig.signalqueue);
|
||||
base->sig.ev_signal_pair[0] = -1;
|
||||
base->sig.ev_signal_pair[1] = -1;
|
||||
|
||||
base->evbase = NULL;
|
||||
for (i = 0; eventops[i] && !base->evbase; i++) {
|
||||
base->evsel = eventops[i];
|
||||
|
||||
base->evbase = base->evsel->init(base);
|
||||
}
|
||||
|
||||
if (base->evbase == NULL)
|
||||
event_errx(1, "%s: no event mechanism available", __func__);
|
||||
|
||||
if (getenv("EVENT_SHOW_METHOD"))
|
||||
event_msgx("libevent using: %s\n",
|
||||
base->evsel->name);
|
||||
|
||||
/* allocate a single active event queue */
|
||||
event_base_priority_init(base, 1);
|
||||
|
||||
return (base);
|
||||
}
|
||||
|
||||
void
|
||||
event_base_free(struct event_base *base)
|
||||
{
|
||||
int i, n_deleted=0;
|
||||
struct event *ev;
|
||||
|
||||
if (base == NULL && current_base)
|
||||
base = current_base;
|
||||
if (base == current_base)
|
||||
current_base = NULL;
|
||||
|
||||
/* XXX(niels) - check for internal events first */
|
||||
assert(base);
|
||||
/* Delete all non-internal events. */
|
||||
for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
|
||||
struct event *next = TAILQ_NEXT(ev, ev_next);
|
||||
if (!(ev->ev_flags & EVLIST_INTERNAL)) {
|
||||
event_del(ev);
|
||||
++n_deleted;
|
||||
}
|
||||
ev = next;
|
||||
}
|
||||
while ((ev = min_heap_top(&base->timeheap)) != NULL) {
|
||||
event_del(ev);
|
||||
++n_deleted;
|
||||
}
|
||||
|
||||
if (n_deleted)
|
||||
event_debug(("%s: %d events were still set in base",
|
||||
__func__, n_deleted));
|
||||
|
||||
if (base->evsel->dealloc != NULL)
|
||||
base->evsel->dealloc(base, base->evbase);
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i)
|
||||
assert(TAILQ_EMPTY(base->activequeues[i]));
|
||||
|
||||
assert(min_heap_empty(&base->timeheap));
|
||||
min_heap_dtor(&base->timeheap);
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i)
|
||||
free(base->activequeues[i]);
|
||||
free(base->activequeues);
|
||||
|
||||
assert(TAILQ_EMPTY(&base->eventqueue));
|
||||
|
||||
free(base);
|
||||
}
|
||||
|
||||
/* reinitialized the event base after a fork */
|
||||
int
|
||||
event_reinit(struct event_base *base)
|
||||
{
|
||||
const struct eventop *evsel = base->evsel;
|
||||
void *evbase = base->evbase;
|
||||
int res = 0;
|
||||
struct event *ev;
|
||||
|
||||
/* check if this event mechanism requires reinit */
|
||||
if (!evsel->need_reinit)
|
||||
return (0);
|
||||
|
||||
if (base->evsel->dealloc != NULL)
|
||||
base->evsel->dealloc(base, base->evbase);
|
||||
base->evbase = evsel->init(base);
|
||||
if (base->evbase == NULL)
|
||||
event_errx(1, "%s: could not reinitialize event mechanism",
|
||||
__func__);
|
||||
|
||||
TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
|
||||
if (evsel->add(evbase, ev) == -1)
|
||||
res = -1;
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
event_priority_init(int npriorities)
|
||||
{
|
||||
return event_base_priority_init(current_base, npriorities);
|
||||
}
|
||||
|
||||
int
|
||||
event_base_priority_init(struct event_base *base, int npriorities)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (base->event_count_active)
|
||||
return (-1);
|
||||
|
||||
if (base->nactivequeues && npriorities != base->nactivequeues) {
|
||||
for (i = 0; i < base->nactivequeues; ++i) {
|
||||
free(base->activequeues[i]);
|
||||
}
|
||||
free(base->activequeues);
|
||||
}
|
||||
|
||||
/* Allocate our priority queues */
|
||||
base->nactivequeues = npriorities;
|
||||
base->activequeues = (struct event_list **)calloc(base->nactivequeues,
|
||||
npriorities * sizeof(struct event_list *));
|
||||
if (base->activequeues == NULL)
|
||||
event_err(1, "%s: calloc", __func__);
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i) {
|
||||
base->activequeues[i] = malloc(sizeof(struct event_list));
|
||||
if (base->activequeues[i] == NULL)
|
||||
event_err(1, "%s: malloc", __func__);
|
||||
TAILQ_INIT(base->activequeues[i]);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
event_haveevents(struct event_base *base)
|
||||
{
|
||||
return (base->event_count > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Active events are stored in priority queues. Lower priorities are always
|
||||
* process before higher priorities. Low priority events can starve high
|
||||
* priority ones.
|
||||
*/
|
||||
|
||||
static void
|
||||
event_process_active(struct event_base *base)
|
||||
{
|
||||
struct event *ev;
|
||||
struct event_list *activeq = NULL;
|
||||
int i;
|
||||
short ncalls;
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i) {
|
||||
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
|
||||
activeq = base->activequeues[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(activeq != NULL);
|
||||
|
||||
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
|
||||
if (ev->ev_events & EV_PERSIST)
|
||||
event_queue_remove(base, ev, EVLIST_ACTIVE);
|
||||
else
|
||||
event_del(ev);
|
||||
|
||||
/* Allows deletes to work */
|
||||
ncalls = ev->ev_ncalls;
|
||||
ev->ev_pncalls = &ncalls;
|
||||
while (ncalls) {
|
||||
ncalls--;
|
||||
ev->ev_ncalls = ncalls;
|
||||
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
|
||||
if (event_gotsig || base->event_break)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait continously for events. We exit only if no events are left.
|
||||
*/
|
||||
|
||||
int
|
||||
event_dispatch(void)
|
||||
{
|
||||
return (event_loop(0));
|
||||
}
|
||||
|
||||
int
|
||||
event_base_dispatch(struct event_base *event_base)
|
||||
{
|
||||
return (event_base_loop(event_base, 0));
|
||||
}
|
||||
|
||||
const char *
|
||||
event_base_get_method(struct event_base *base)
|
||||
{
|
||||
assert(base);
|
||||
return (base->evsel->name);
|
||||
}
|
||||
|
||||
static void
|
||||
event_loopexit_cb(int fd __attribute__((unused)),
|
||||
short what __attribute__((unused)), void *arg)
|
||||
{
|
||||
struct event_base *base = arg;
|
||||
base->event_gotterm = 1;
|
||||
}
|
||||
|
||||
/* not thread safe */
|
||||
int
|
||||
event_loopexit(struct timeval *tv)
|
||||
{
|
||||
return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
|
||||
current_base, tv));
|
||||
}
|
||||
|
||||
int
|
||||
event_base_loopexit(struct event_base *event_base, struct timeval *tv)
|
||||
{
|
||||
return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
|
||||
event_base, tv));
|
||||
}
|
||||
|
||||
/* not thread safe */
|
||||
int
|
||||
event_loopbreak(void)
|
||||
{
|
||||
return (event_base_loopbreak(current_base));
|
||||
}
|
||||
|
||||
int
|
||||
event_base_loopbreak(struct event_base *event_base)
|
||||
{
|
||||
if (event_base == NULL)
|
||||
return (-1);
|
||||
|
||||
event_base->event_break = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* not thread safe */
|
||||
|
||||
int
|
||||
event_loop(int flags)
|
||||
{
|
||||
return event_base_loop(current_base, flags);
|
||||
}
|
||||
|
||||
int
|
||||
event_base_loop(struct event_base *base, int flags)
|
||||
{
|
||||
const struct eventop *evsel = base->evsel;
|
||||
void *evbase = base->evbase;
|
||||
struct timeval tv;
|
||||
struct timeval *tv_p;
|
||||
int res, done;
|
||||
|
||||
if(!TAILQ_EMPTY(&base->sig.signalqueue))
|
||||
evsignal_base = base;
|
||||
done = 0;
|
||||
while (!done) {
|
||||
/* Terminate the loop if we have been asked to */
|
||||
if (base->event_gotterm) {
|
||||
base->event_gotterm = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (base->event_break) {
|
||||
base->event_break = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* You cannot use this interface for multi-threaded apps */
|
||||
while (event_gotsig) {
|
||||
event_gotsig = 0;
|
||||
if (event_sigcb) {
|
||||
res = (*event_sigcb)();
|
||||
if (res == -1) {
|
||||
errno = EINTR;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timeout_correct(base, &tv);
|
||||
|
||||
tv_p = &tv;
|
||||
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
|
||||
timeout_next(base, &tv_p);
|
||||
} else {
|
||||
/*
|
||||
* if we have active events, we just poll new events
|
||||
* without waiting.
|
||||
*/
|
||||
evutil_timerclear(&tv);
|
||||
}
|
||||
|
||||
/* If we have no events, we just exit */
|
||||
if (!event_haveevents(base)) {
|
||||
event_debug(("%s: no events registered.", __func__));
|
||||
return (1);
|
||||
}
|
||||
|
||||
res = evsel->dispatch(base, evbase, tv_p);
|
||||
|
||||
if (res == -1)
|
||||
return (-1);
|
||||
|
||||
timeout_process(base);
|
||||
|
||||
if (base->event_count_active) {
|
||||
event_process_active(base);
|
||||
if (!base->event_count_active && (flags & EVLOOP_ONCE))
|
||||
done = 1;
|
||||
} else if (flags & EVLOOP_NONBLOCK)
|
||||
done = 1;
|
||||
}
|
||||
|
||||
event_debug(("%s: asked to terminate loop.", __func__));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Sets up an event for processing once */
|
||||
|
||||
struct event_once {
|
||||
struct event ev;
|
||||
|
||||
void (*cb)(int, short, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
/* One-time callback, it deletes itself */
|
||||
|
||||
static void
|
||||
event_once_cb(int fd, short events, void *arg)
|
||||
{
|
||||
struct event_once *eonce = arg;
|
||||
|
||||
(*eonce->cb)(fd, events, eonce->arg);
|
||||
free(eonce);
|
||||
}
|
||||
|
||||
/* not threadsafe, event scheduled once. */
|
||||
int
|
||||
event_once(int fd, short events,
|
||||
void (*callback)(int, short, void *), void *arg, struct timeval *tv)
|
||||
{
|
||||
return event_base_once(current_base, fd, events, callback, arg, tv);
|
||||
}
|
||||
|
||||
/* Schedules an event once */
|
||||
int
|
||||
event_base_once(struct event_base *base, int fd, short events,
|
||||
void (*callback)(int, short, void *), void *arg, struct timeval *tv)
|
||||
{
|
||||
struct event_once *eonce;
|
||||
struct timeval etv;
|
||||
int res;
|
||||
|
||||
/* We cannot support signals that just fire once */
|
||||
if (events & EV_SIGNAL)
|
||||
return (-1);
|
||||
|
||||
if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
|
||||
return (-1);
|
||||
|
||||
eonce->cb = callback;
|
||||
eonce->arg = arg;
|
||||
|
||||
if (events == EV_TIMEOUT) {
|
||||
if (tv == NULL) {
|
||||
evutil_timerclear(&etv);
|
||||
tv = &etv;
|
||||
}
|
||||
|
||||
evtimer_set(&eonce->ev, event_once_cb, eonce);
|
||||
} else if (events & (EV_READ|EV_WRITE)) {
|
||||
events &= EV_READ|EV_WRITE;
|
||||
|
||||
event_set(&eonce->ev, fd, events, event_once_cb, eonce);
|
||||
} else {
|
||||
/* Bad event combination */
|
||||
free(eonce);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = event_base_set(base, &eonce->ev);
|
||||
if (res == 0)
|
||||
res = event_add(&eonce->ev, tv);
|
||||
if (res != 0) {
|
||||
free(eonce);
|
||||
return (res);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
event_set(struct event *ev, int fd, short events,
|
||||
void (*callback)(int, short, void *), void *arg)
|
||||
{
|
||||
/* Take the current base - caller needs to set the real base later */
|
||||
ev->ev_base = current_base;
|
||||
|
||||
ev->ev_callback = callback;
|
||||
ev->ev_arg = arg;
|
||||
ev->ev_fd = fd;
|
||||
ev->ev_events = events;
|
||||
ev->ev_res = 0;
|
||||
ev->ev_flags = EVLIST_INIT;
|
||||
ev->ev_ncalls = 0;
|
||||
ev->ev_pncalls = NULL;
|
||||
|
||||
min_heap_elem_init(ev);
|
||||
|
||||
/* by default, we put new events into the middle priority */
|
||||
if(current_base)
|
||||
ev->ev_pri = current_base->nactivequeues/2;
|
||||
}
|
||||
|
||||
int
|
||||
event_base_set(struct event_base *base, struct event *ev)
|
||||
{
|
||||
/* Only innocent events may be assigned to a different base */
|
||||
if (ev->ev_flags != EVLIST_INIT)
|
||||
return (-1);
|
||||
|
||||
ev->ev_base = base;
|
||||
ev->ev_pri = base->nactivequeues/2;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set's the priority of an event - if an event is already scheduled
|
||||
* changing the priority is going to fail.
|
||||
*/
|
||||
|
||||
int
|
||||
event_priority_set(struct event *ev, int pri)
|
||||
{
|
||||
if (ev->ev_flags & EVLIST_ACTIVE)
|
||||
return (-1);
|
||||
if (pri < 0 || pri >= ev->ev_base->nactivequeues)
|
||||
return (-1);
|
||||
|
||||
ev->ev_pri = pri;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a specific event is pending or scheduled.
|
||||
*/
|
||||
|
||||
int
|
||||
event_pending(struct event *ev, short event, struct timeval *tv)
|
||||
{
|
||||
struct timeval now, res;
|
||||
int flags = 0;
|
||||
|
||||
if (ev->ev_flags & EVLIST_INSERTED)
|
||||
flags |= (ev->ev_events & (EV_READ|EV_WRITE));
|
||||
if (ev->ev_flags & EVLIST_ACTIVE)
|
||||
flags |= ev->ev_res;
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
flags |= EV_TIMEOUT;
|
||||
if (ev->ev_flags & EVLIST_SIGNAL)
|
||||
flags |= EV_SIGNAL;
|
||||
|
||||
event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
|
||||
|
||||
/* See if there is a timeout that we should report */
|
||||
if (tv != NULL && (flags & event & EV_TIMEOUT)) {
|
||||
gettime(&now);
|
||||
evutil_timersub(&ev->ev_timeout, &now, &res);
|
||||
/* correctly remap to real time */
|
||||
gettimeofday(&now, NULL);
|
||||
evutil_timeradd(&now, &res, tv);
|
||||
}
|
||||
|
||||
return (flags & event);
|
||||
}
|
||||
|
||||
int
|
||||
event_add(struct event *ev, struct timeval *tv)
|
||||
{
|
||||
struct event_base *base = ev->ev_base;
|
||||
const struct eventop *evsel = base->evsel;
|
||||
void *evbase = base->evbase;
|
||||
|
||||
event_debug((
|
||||
"event_add: event: %p, %s%s%scall %p",
|
||||
ev,
|
||||
ev->ev_events & EV_READ ? "EV_READ " : " ",
|
||||
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
|
||||
tv ? "EV_TIMEOUT " : " ",
|
||||
ev->ev_callback));
|
||||
|
||||
assert(!(ev->ev_flags & ~EVLIST_ALL));
|
||||
|
||||
if (tv != NULL) {
|
||||
struct timeval now;
|
||||
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
event_queue_remove(base, ev, EVLIST_TIMEOUT);
|
||||
else if (min_heap_reserve(&base->timeheap,
|
||||
1 + min_heap_size(&base->timeheap)) == -1)
|
||||
return (-1); /* ENOMEM == errno */
|
||||
|
||||
/* Check if it is active due to a timeout. Rescheduling
|
||||
* this timeout before the callback can be executed
|
||||
* removes it from the active list. */
|
||||
if ((ev->ev_flags & EVLIST_ACTIVE) &&
|
||||
(ev->ev_res & EV_TIMEOUT)) {
|
||||
/* See if we are just active executing this
|
||||
* event in a loop
|
||||
*/
|
||||
if (ev->ev_ncalls && ev->ev_pncalls) {
|
||||
/* Abort loop */
|
||||
*ev->ev_pncalls = 0;
|
||||
}
|
||||
|
||||
event_queue_remove(base, ev, EVLIST_ACTIVE);
|
||||
}
|
||||
|
||||
gettime(&now);
|
||||
evutil_timeradd(&now, tv, &ev->ev_timeout);
|
||||
|
||||
event_debug((
|
||||
"event_add: timeout in %d seconds, call %p",
|
||||
tv->tv_sec, ev->ev_callback));
|
||||
|
||||
event_queue_insert(base, ev, EVLIST_TIMEOUT);
|
||||
}
|
||||
|
||||
if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
|
||||
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
|
||||
int res = evsel->add(evbase, ev);
|
||||
if (res != -1)
|
||||
event_queue_insert(base, ev, EVLIST_INSERTED);
|
||||
|
||||
return (res);
|
||||
} else if ((ev->ev_events & EV_SIGNAL) &&
|
||||
!(ev->ev_flags & EVLIST_SIGNAL)) {
|
||||
int res = evsel->add(evbase, ev);
|
||||
if (res != -1)
|
||||
event_queue_insert(base, ev, EVLIST_SIGNAL);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
event_del(struct event *ev)
|
||||
{
|
||||
struct event_base *base;
|
||||
const struct eventop *evsel;
|
||||
void *evbase;
|
||||
|
||||
event_debug(("event_del: %p, callback %p",
|
||||
ev, ev->ev_callback));
|
||||
|
||||
/* An event without a base has not been added */
|
||||
if (ev->ev_base == NULL)
|
||||
return (-1);
|
||||
|
||||
base = ev->ev_base;
|
||||
evsel = base->evsel;
|
||||
evbase = base->evbase;
|
||||
|
||||
assert(!(ev->ev_flags & ~EVLIST_ALL));
|
||||
|
||||
/* See if we are just active executing this event in a loop */
|
||||
if (ev->ev_ncalls && ev->ev_pncalls) {
|
||||
/* Abort loop */
|
||||
*ev->ev_pncalls = 0;
|
||||
}
|
||||
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
event_queue_remove(base, ev, EVLIST_TIMEOUT);
|
||||
|
||||
if (ev->ev_flags & EVLIST_ACTIVE)
|
||||
event_queue_remove(base, ev, EVLIST_ACTIVE);
|
||||
|
||||
if (ev->ev_flags & EVLIST_INSERTED) {
|
||||
event_queue_remove(base, ev, EVLIST_INSERTED);
|
||||
return (evsel->del(evbase, ev));
|
||||
} else if (ev->ev_flags & EVLIST_SIGNAL) {
|
||||
event_queue_remove(base, ev, EVLIST_SIGNAL);
|
||||
return (evsel->del(evbase, ev));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
event_active(struct event *ev, int res, short ncalls)
|
||||
{
|
||||
/* We get different kinds of events, add them together */
|
||||
if (ev->ev_flags & EVLIST_ACTIVE) {
|
||||
ev->ev_res |= res;
|
||||
return;
|
||||
}
|
||||
|
||||
ev->ev_res = res;
|
||||
ev->ev_ncalls = ncalls;
|
||||
ev->ev_pncalls = NULL;
|
||||
event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
|
||||
}
|
||||
|
||||
static int
|
||||
timeout_next(struct event_base *base, struct timeval **tv_p)
|
||||
{
|
||||
struct timeval now;
|
||||
struct event *ev;
|
||||
struct timeval *tv = *tv_p;
|
||||
|
||||
if ((ev = min_heap_top(&base->timeheap)) == NULL) {
|
||||
/* if no time-based events are active wait for I/O */
|
||||
*tv_p = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (gettime(&now) == -1)
|
||||
return (-1);
|
||||
|
||||
if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
|
||||
evutil_timerclear(tv);
|
||||
return (0);
|
||||
}
|
||||
|
||||
evutil_timersub(&ev->ev_timeout, &now, tv);
|
||||
|
||||
assert(tv->tv_sec >= 0);
|
||||
assert(tv->tv_usec >= 0);
|
||||
|
||||
event_debug(("timeout_next: in %d seconds", tv->tv_sec));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the time is running backwards by comparing the current
|
||||
* time against the last time we checked. Not needed when using clock
|
||||
* monotonic.
|
||||
*/
|
||||
|
||||
static void
|
||||
timeout_correct(struct event_base *base, struct timeval *tv)
|
||||
{
|
||||
struct event **pev;
|
||||
unsigned int size;
|
||||
struct timeval off;
|
||||
|
||||
if (use_monotonic)
|
||||
return;
|
||||
|
||||
/* Check if time is running backwards */
|
||||
gettime(tv);
|
||||
if (evutil_timercmp(tv, &base->event_tv, >=)) {
|
||||
base->event_tv = *tv;
|
||||
return;
|
||||
}
|
||||
|
||||
event_debug(("%s: time is running backwards, corrected",
|
||||
__func__));
|
||||
evutil_timersub(&base->event_tv, tv, &off);
|
||||
|
||||
/*
|
||||
* We can modify the key element of the node without destroying
|
||||
* the key, beause we apply it to all in the right order.
|
||||
*/
|
||||
pev = base->timeheap.p;
|
||||
size = base->timeheap.n;
|
||||
for (; size-- > 0; ++pev) {
|
||||
struct timeval *ev_tv = &(**pev).ev_timeout;
|
||||
evutil_timersub(ev_tv, &off, ev_tv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timeout_process(struct event_base *base)
|
||||
{
|
||||
struct timeval now;
|
||||
struct event *ev;
|
||||
|
||||
if (min_heap_empty(&base->timeheap))
|
||||
return;
|
||||
|
||||
gettime(&now);
|
||||
|
||||
while ((ev = min_heap_top(&base->timeheap))) {
|
||||
if (evutil_timercmp(&ev->ev_timeout, &now, >))
|
||||
break;
|
||||
|
||||
/* delete this event from the I/O queues */
|
||||
event_del(ev);
|
||||
|
||||
event_debug(("timeout_process: call %p",
|
||||
ev->ev_callback));
|
||||
event_active(ev, EV_TIMEOUT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_queue_remove(struct event_base *base, struct event *ev, int queue)
|
||||
{
|
||||
if (!(ev->ev_flags & queue))
|
||||
event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
|
||||
ev, ev->ev_fd, queue);
|
||||
|
||||
if (~ev->ev_flags & EVLIST_INTERNAL)
|
||||
base->event_count--;
|
||||
|
||||
ev->ev_flags &= ~queue;
|
||||
switch (queue) {
|
||||
case EVLIST_ACTIVE:
|
||||
base->event_count_active--;
|
||||
TAILQ_REMOVE(base->activequeues[ev->ev_pri],
|
||||
ev, ev_active_next);
|
||||
break;
|
||||
case EVLIST_SIGNAL:
|
||||
TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
|
||||
break;
|
||||
case EVLIST_TIMEOUT:
|
||||
min_heap_erase(&base->timeheap, ev);
|
||||
break;
|
||||
case EVLIST_INSERTED:
|
||||
TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
|
||||
break;
|
||||
default:
|
||||
event_errx(1, "%s: unknown queue %x", __func__, queue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_queue_insert(struct event_base *base, struct event *ev, int queue)
|
||||
{
|
||||
if (ev->ev_flags & queue) {
|
||||
/* Double insertion is possible for active events */
|
||||
if (queue & EVLIST_ACTIVE)
|
||||
return;
|
||||
|
||||
event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
|
||||
ev, ev->ev_fd, queue);
|
||||
}
|
||||
|
||||
if (~ev->ev_flags & EVLIST_INTERNAL)
|
||||
base->event_count++;
|
||||
|
||||
ev->ev_flags |= queue;
|
||||
switch (queue) {
|
||||
case EVLIST_ACTIVE:
|
||||
base->event_count_active++;
|
||||
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
|
||||
ev,ev_active_next);
|
||||
break;
|
||||
case EVLIST_SIGNAL:
|
||||
TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
|
||||
break;
|
||||
case EVLIST_TIMEOUT: {
|
||||
min_heap_push(&base->timeheap, ev);
|
||||
break;
|
||||
}
|
||||
case EVLIST_INSERTED:
|
||||
TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
|
||||
break;
|
||||
default:
|
||||
event_errx(1, "%s: unknown queue %x", __func__, queue);
|
||||
}
|
||||
}
|
||||
|
||||
/* Functions for debugging */
|
||||
|
||||
const char *
|
||||
event_get_version(void)
|
||||
{
|
||||
return (VERSION);
|
||||
}
|
||||
|
||||
/*
|
||||
* No thread-safe interface needed - the information should be the same
|
||||
* for all threads.
|
||||
*/
|
||||
|
||||
const char *
|
||||
event_get_method(void)
|
||||
{
|
||||
return (current_base->evsel->name);
|
||||
}
|
||||
1129
extra/libevent/event.h
Normal file
1129
extra/libevent/event.h
Normal file
File diff suppressed because it is too large
Load Diff
443
extra/libevent/event_tagging.c
Normal file
443
extra/libevent/event_tagging.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <sys/queue.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "evutil.h"
|
||||
#include "log.h"
|
||||
|
||||
int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
|
||||
int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
|
||||
int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
|
||||
|
||||
static struct evbuffer *_buf; /* not thread safe */
|
||||
|
||||
void
|
||||
evtag_init(void)
|
||||
{
|
||||
if (_buf != NULL)
|
||||
return;
|
||||
|
||||
if ((_buf = evbuffer_new()) == NULL)
|
||||
event_err(1, "%s: malloc", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* We encode integer's by nibbles; the first nibble contains the number
|
||||
* of significant nibbles - 1; this allows us to encode up to 64-bit
|
||||
* integers. This function is byte-order independent.
|
||||
*/
|
||||
|
||||
void
|
||||
encode_int(struct evbuffer *evbuf, ev_uint32_t number)
|
||||
{
|
||||
int off = 1, nibbles = 0;
|
||||
ev_uint8_t data[5];
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
while (number) {
|
||||
if (off & 0x1)
|
||||
data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
|
||||
else
|
||||
data[off/2] = (data[off/2] & 0x0f) |
|
||||
((number & 0x0f) << 4);
|
||||
number >>= 4;
|
||||
off++;
|
||||
}
|
||||
|
||||
if (off > 2)
|
||||
nibbles = off - 2;
|
||||
|
||||
/* Off - 1 is the number of encoded nibbles */
|
||||
data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);
|
||||
|
||||
evbuffer_add(evbuf, data, (off + 1) / 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Support variable length encoding of tags; we use the high bit in each
|
||||
* octet as a continuation signal.
|
||||
*/
|
||||
|
||||
int
|
||||
evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
|
||||
{
|
||||
int bytes = 0;
|
||||
ev_uint8_t data[5];
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
do {
|
||||
ev_uint8_t lower = tag & 0x7f;
|
||||
tag >>= 7;
|
||||
|
||||
if (tag)
|
||||
lower |= 0x80;
|
||||
|
||||
data[bytes++] = lower;
|
||||
} while (tag);
|
||||
|
||||
if (evbuf != NULL)
|
||||
evbuffer_add(evbuf, data, bytes);
|
||||
|
||||
return (bytes);
|
||||
}
|
||||
|
||||
static int
|
||||
decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
|
||||
{
|
||||
ev_uint32_t number = 0;
|
||||
ev_uint8_t *data = EVBUFFER_DATA(evbuf);
|
||||
int len = EVBUFFER_LENGTH(evbuf);
|
||||
int count = 0, shift = 0, done = 0;
|
||||
|
||||
while (count++ < len) {
|
||||
ev_uint8_t lower = *data++;
|
||||
number |= (lower & 0x7f) << shift;
|
||||
shift += 7;
|
||||
|
||||
if (!(lower & 0x80)) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done)
|
||||
return (-1);
|
||||
|
||||
if (dodrain)
|
||||
evbuffer_drain(evbuf, count);
|
||||
|
||||
if (ptag != NULL)
|
||||
*ptag = number;
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
|
||||
{
|
||||
return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
|
||||
}
|
||||
|
||||
/*
|
||||
* Marshal a data type, the general format is as follows:
|
||||
*
|
||||
* tag number: one byte; length: var bytes; payload: var bytes
|
||||
*/
|
||||
|
||||
void
|
||||
evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
|
||||
const void *data, ev_uint32_t len)
|
||||
{
|
||||
evtag_encode_tag(evbuf, tag);
|
||||
encode_int(evbuf, len);
|
||||
evbuffer_add(evbuf, (void *)data, len);
|
||||
}
|
||||
|
||||
/* Marshaling for integers */
|
||||
void
|
||||
evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
|
||||
{
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
encode_int(_buf, integer);
|
||||
|
||||
evtag_encode_tag(evbuf, tag);
|
||||
encode_int(evbuf, EVBUFFER_LENGTH(_buf));
|
||||
evbuffer_add_buffer(evbuf, _buf);
|
||||
}
|
||||
|
||||
void
|
||||
evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
|
||||
{
|
||||
evtag_marshal(buf, tag, string, strlen(string));
|
||||
}
|
||||
|
||||
void
|
||||
evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
|
||||
{
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
|
||||
encode_int(_buf, tv->tv_sec);
|
||||
encode_int(_buf, tv->tv_usec);
|
||||
|
||||
evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf),
|
||||
EVBUFFER_LENGTH(_buf));
|
||||
}
|
||||
|
||||
static int
|
||||
decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
|
||||
{
|
||||
ev_uint32_t number = 0;
|
||||
ev_uint8_t *data = EVBUFFER_DATA(evbuf);
|
||||
int len = EVBUFFER_LENGTH(evbuf);
|
||||
int nibbles = 0;
|
||||
|
||||
if (!len)
|
||||
return (-1);
|
||||
|
||||
nibbles = ((data[0] & 0xf0) >> 4) + 1;
|
||||
if (nibbles > 8 || (nibbles >> 1) + 1 > len)
|
||||
return (-1);
|
||||
len = (nibbles >> 1) + 1;
|
||||
|
||||
while (nibbles > 0) {
|
||||
number <<= 4;
|
||||
if (nibbles & 0x1)
|
||||
number |= data[nibbles >> 1] & 0x0f;
|
||||
else
|
||||
number |= (data[nibbles >> 1] & 0xf0) >> 4;
|
||||
nibbles--;
|
||||
}
|
||||
|
||||
if (dodrain)
|
||||
evbuffer_drain(evbuf, len);
|
||||
|
||||
*pnumber = number;
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
|
||||
{
|
||||
return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
|
||||
{
|
||||
return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
|
||||
}
|
||||
|
||||
int
|
||||
evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
|
||||
{
|
||||
struct evbuffer tmp;
|
||||
int res, len;
|
||||
|
||||
len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
|
||||
if (len == -1)
|
||||
return (-1);
|
||||
|
||||
tmp = *evbuf;
|
||||
tmp.buffer += len;
|
||||
tmp.off -= len;
|
||||
|
||||
res = decode_int_internal(plength, &tmp, 0);
|
||||
if (res == -1)
|
||||
return (-1);
|
||||
|
||||
*plength += res + len;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
|
||||
{
|
||||
struct evbuffer tmp;
|
||||
int res, len;
|
||||
|
||||
len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
|
||||
if (len == -1)
|
||||
return (-1);
|
||||
|
||||
tmp = *evbuf;
|
||||
tmp.buffer += len;
|
||||
tmp.off -= len;
|
||||
|
||||
res = decode_int_internal(plength, &tmp, 0);
|
||||
if (res == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_consume(struct evbuffer *evbuf)
|
||||
{
|
||||
ev_uint32_t len;
|
||||
if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
|
||||
return (-1);
|
||||
if (evtag_decode_int(&len, evbuf) == -1)
|
||||
return (-1);
|
||||
evbuffer_drain(evbuf, len);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Reads the data type from an event buffer */
|
||||
|
||||
int
|
||||
evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
|
||||
{
|
||||
ev_uint32_t len;
|
||||
ev_uint32_t integer;
|
||||
|
||||
if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
|
||||
return (-1);
|
||||
if (evtag_decode_int(&integer, src) == -1)
|
||||
return (-1);
|
||||
len = integer;
|
||||
|
||||
if (EVBUFFER_LENGTH(src) < len)
|
||||
return (-1);
|
||||
|
||||
if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1)
|
||||
return (-1);
|
||||
|
||||
evbuffer_drain(src, len);
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
/* Marshaling for integers */
|
||||
|
||||
int
|
||||
evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
|
||||
ev_uint32_t *pinteger)
|
||||
{
|
||||
ev_uint32_t tag;
|
||||
ev_uint32_t len;
|
||||
ev_uint32_t integer;
|
||||
|
||||
if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
|
||||
return (-1);
|
||||
if (need_tag != tag)
|
||||
return (-1);
|
||||
if (evtag_decode_int(&integer, evbuf) == -1)
|
||||
return (-1);
|
||||
len = integer;
|
||||
|
||||
if (EVBUFFER_LENGTH(evbuf) < len)
|
||||
return (-1);
|
||||
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1)
|
||||
return (-1);
|
||||
|
||||
evbuffer_drain(evbuf, len);
|
||||
|
||||
return (evtag_decode_int(pinteger, _buf));
|
||||
}
|
||||
|
||||
/* Unmarshal a fixed length tag */
|
||||
|
||||
int
|
||||
evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
|
||||
size_t len)
|
||||
{
|
||||
ev_uint32_t tag;
|
||||
|
||||
/* Initialize this event buffer so that we can read into it */
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
|
||||
/* Now unmarshal a tag and check that it matches the tag we want */
|
||||
if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag)
|
||||
return (-1);
|
||||
|
||||
if (EVBUFFER_LENGTH(_buf) != len)
|
||||
return (-1);
|
||||
|
||||
memcpy(data, EVBUFFER_DATA(_buf), len);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
|
||||
char **pstring)
|
||||
{
|
||||
ev_uint32_t tag;
|
||||
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
|
||||
if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
|
||||
return (-1);
|
||||
|
||||
*pstring = calloc(EVBUFFER_LENGTH(_buf) + 1, 1);
|
||||
if (*pstring == NULL)
|
||||
event_err(1, "%s: calloc", __func__);
|
||||
evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
|
||||
struct timeval *ptv)
|
||||
{
|
||||
ev_uint32_t tag;
|
||||
ev_uint32_t integer;
|
||||
|
||||
evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
|
||||
if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
|
||||
return (-1);
|
||||
|
||||
if (evtag_decode_int(&integer, _buf) == -1)
|
||||
return (-1);
|
||||
ptv->tv_sec = integer;
|
||||
if (evtag_decode_int(&integer, _buf) == -1)
|
||||
return (-1);
|
||||
ptv->tv_usec = integer;
|
||||
|
||||
return (0);
|
||||
}
|
||||
340
extra/libevent/evhttp.h
Normal file
340
extra/libevent/evhttp.h
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVHTTP_H_
|
||||
#define _EVHTTP_H_
|
||||
|
||||
#include <event.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/** @file evhttp.h
|
||||
*
|
||||
* Basic support for HTTP serving.
|
||||
*
|
||||
* As libevent is a library for dealing with event notification and most
|
||||
* interesting applications are networked today, I have often found the
|
||||
* need to write HTTP code. The following prototypes and definitions provide
|
||||
* an application with a minimal interface for making HTTP requests and for
|
||||
* creating a very simple HTTP server.
|
||||
*/
|
||||
|
||||
/* Response codes */
|
||||
#define HTTP_OK 200
|
||||
#define HTTP_NOCONTENT 204
|
||||
#define HTTP_MOVEPERM 301
|
||||
#define HTTP_MOVETEMP 302
|
||||
#define HTTP_NOTMODIFIED 304
|
||||
#define HTTP_BADREQUEST 400
|
||||
#define HTTP_NOTFOUND 404
|
||||
#define HTTP_SERVUNAVAIL 503
|
||||
|
||||
struct evhttp;
|
||||
struct evhttp_request;
|
||||
struct evkeyvalq;
|
||||
|
||||
/** Create a new HTTP server
|
||||
*
|
||||
* @param base (optional) the event base to receive the HTTP events
|
||||
* @return a pointer to a newly initialized evhttp server structure
|
||||
*/
|
||||
struct evhttp *evhttp_new(struct event_base *base);
|
||||
|
||||
/**
|
||||
* Binds an HTTP server on the specified address and port.
|
||||
*
|
||||
* Can be called multiple times to bind the same http server
|
||||
* to multiple different ports.
|
||||
*
|
||||
* @param http a pointer to an evhttp object
|
||||
* @param address a string containing the IP address to listen(2) on
|
||||
* @param port the port number to listen on
|
||||
* @return a newly allocated evhttp struct
|
||||
* @see evhttp_free()
|
||||
*/
|
||||
int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
|
||||
|
||||
/**
|
||||
* Free the previously created HTTP server.
|
||||
*
|
||||
* Works only if no requests are currently being served.
|
||||
*
|
||||
* @param http the evhttp server object to be freed
|
||||
* @see evhttp_start()
|
||||
*/
|
||||
void evhttp_free(struct evhttp* http);
|
||||
|
||||
/** Set a callback for a specified URI */
|
||||
void evhttp_set_cb(struct evhttp *, const char *,
|
||||
void (*)(struct evhttp_request *, void *), void *);
|
||||
|
||||
/** Removes the callback for a specified URI */
|
||||
int evhttp_del_cb(struct evhttp *, const char *);
|
||||
|
||||
/** Set a callback for all requests that are not caught by specific callbacks
|
||||
*/
|
||||
void evhttp_set_gencb(struct evhttp *,
|
||||
void (*)(struct evhttp_request *, void *), void *);
|
||||
|
||||
/**
|
||||
* Set the timeout for an HTTP request.
|
||||
*
|
||||
* @param http an evhttp object
|
||||
* @param timeout_in_secs the timeout, in seconds
|
||||
*/
|
||||
void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
|
||||
|
||||
/* Request/Response functionality */
|
||||
|
||||
/**
|
||||
* Send an HTML error message to the client.
|
||||
*
|
||||
* @param req a request object
|
||||
* @param error the HTTP error code
|
||||
* @param reason a brief explanation of the error
|
||||
*/
|
||||
void evhttp_send_error(struct evhttp_request *req, int error,
|
||||
const char *reason);
|
||||
|
||||
/**
|
||||
* Send an HTML reply to the client.
|
||||
*
|
||||
* @param req a request object
|
||||
* @param code the HTTP response code to send
|
||||
* @param reason a brief message to send with the response code
|
||||
* @param databuf the body of the response
|
||||
*/
|
||||
void evhttp_send_reply(struct evhttp_request *req, int code,
|
||||
const char *reason, struct evbuffer *databuf);
|
||||
|
||||
/* Low-level response interface, for streaming/chunked replies */
|
||||
void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
|
||||
void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
|
||||
void evhttp_send_reply_end(struct evhttp_request *);
|
||||
|
||||
/**
|
||||
* Start an HTTP server on the specified address and port
|
||||
*
|
||||
* DEPRECATED: it does not allow an event base to be specified
|
||||
*
|
||||
* @param address the address to which the HTTP server should be bound
|
||||
* @param port the port number on which the HTTP server should listen
|
||||
* @return an struct evhttp object
|
||||
*/
|
||||
struct evhttp *evhttp_start(const char *address, u_short port);
|
||||
|
||||
/*
|
||||
* Interfaces for making requests
|
||||
*/
|
||||
enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
|
||||
|
||||
enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
|
||||
|
||||
/**
|
||||
* the request structure that a server receives.
|
||||
* WARNING: expect this structure to change. I will try to provide
|
||||
* reasonable accessors.
|
||||
*/
|
||||
struct evhttp_request {
|
||||
#if defined(TAILQ_ENTRY)
|
||||
TAILQ_ENTRY(evhttp_request) next;
|
||||
#else
|
||||
struct {
|
||||
struct evhttp_request *tqe_next;
|
||||
struct evhttp_request **tqe_prev;
|
||||
} next;
|
||||
#endif
|
||||
|
||||
/* the connection object that this request belongs to */
|
||||
struct evhttp_connection *evcon;
|
||||
int flags;
|
||||
#define EVHTTP_REQ_OWN_CONNECTION 0x0001
|
||||
#define EVHTTP_PROXY_REQUEST 0x0002
|
||||
|
||||
struct evkeyvalq *input_headers;
|
||||
struct evkeyvalq *output_headers;
|
||||
|
||||
/* address of the remote host and the port connection came from */
|
||||
char *remote_host;
|
||||
u_short remote_port;
|
||||
|
||||
enum evhttp_request_kind kind;
|
||||
enum evhttp_cmd_type type;
|
||||
|
||||
char *uri; /* uri after HTTP request was parsed */
|
||||
|
||||
char major; /* HTTP Major number */
|
||||
char minor; /* HTTP Minor number */
|
||||
|
||||
int got_firstline;
|
||||
int response_code; /* HTTP Response code */
|
||||
char *response_code_line; /* Readable response */
|
||||
|
||||
struct evbuffer *input_buffer; /* read data */
|
||||
ev_int64_t ntoread;
|
||||
int chunked;
|
||||
|
||||
struct evbuffer *output_buffer; /* outgoing post or data */
|
||||
|
||||
/* Callback */
|
||||
void (*cb)(struct evhttp_request *, void *);
|
||||
void *cb_arg;
|
||||
|
||||
/*
|
||||
* Chunked data callback - call for each completed chunk if
|
||||
* specified. If not specified, all the data is delivered via
|
||||
* the regular callback.
|
||||
*/
|
||||
void (*chunk_cb)(struct evhttp_request *, void *);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new request object that needs to be filled in with the request
|
||||
* parameters. The callback is executed when the request completed or an
|
||||
* error occurred.
|
||||
*/
|
||||
struct evhttp_request *evhttp_request_new(
|
||||
void (*cb)(struct evhttp_request *, void *), void *arg);
|
||||
|
||||
/** enable delivery of chunks to requestor */
|
||||
void evhttp_request_set_chunked_cb(struct evhttp_request *,
|
||||
void (*cb)(struct evhttp_request *, void *));
|
||||
|
||||
/** Frees the request object and removes associated events. */
|
||||
void evhttp_request_free(struct evhttp_request *req);
|
||||
|
||||
/**
|
||||
* A connection object that can be used to for making HTTP requests. The
|
||||
* connection object tries to establish the connection when it is given an
|
||||
* http request object.
|
||||
*/
|
||||
struct evhttp_connection *evhttp_connection_new(
|
||||
const char *address, unsigned short port);
|
||||
|
||||
/** Frees an http connection */
|
||||
void evhttp_connection_free(struct evhttp_connection *evcon);
|
||||
|
||||
/** sets the ip address from which http connections are made */
|
||||
void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
|
||||
const char *address);
|
||||
|
||||
/** Sets the timeout for events related to this connection */
|
||||
void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
|
||||
int timeout_in_secs);
|
||||
|
||||
/** Sets the retry limit for this connection - -1 repeats indefnitely */
|
||||
void evhttp_connection_set_retries(struct evhttp_connection *evcon,
|
||||
int retry_max);
|
||||
|
||||
/** Set a callback for connection close. */
|
||||
void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
|
||||
void (*)(struct evhttp_connection *, void *), void *);
|
||||
|
||||
/**
|
||||
* Associates an event base with the connection - can only be called
|
||||
* on a freshly created connection object that has not been used yet.
|
||||
*/
|
||||
void evhttp_connection_set_base(struct evhttp_connection *evcon,
|
||||
struct event_base *base);
|
||||
|
||||
/** Get the remote address and port associated with this connection. */
|
||||
void evhttp_connection_get_peer(struct evhttp_connection *evcon,
|
||||
char **address, u_short *port);
|
||||
|
||||
/** The connection gets ownership of the request */
|
||||
int evhttp_make_request(struct evhttp_connection *evcon,
|
||||
struct evhttp_request *req,
|
||||
enum evhttp_cmd_type type, const char *uri);
|
||||
|
||||
const char *evhttp_request_uri(struct evhttp_request *req);
|
||||
|
||||
/* Interfaces for dealing with HTTP headers */
|
||||
|
||||
const char *evhttp_find_header(const struct evkeyvalq *, const char *);
|
||||
int evhttp_remove_header(struct evkeyvalq *, const char *);
|
||||
int evhttp_add_header(struct evkeyvalq *, const char *, const char *);
|
||||
void evhttp_clear_headers(struct evkeyvalq *);
|
||||
|
||||
/* Miscellaneous utility functions */
|
||||
|
||||
|
||||
/**
|
||||
Helper function to encode a URI.
|
||||
|
||||
The returned string must be freed by the caller.
|
||||
|
||||
@param uri an unencoded URI
|
||||
@return a newly allocated URI-encoded string
|
||||
*/
|
||||
char *evhttp_encode_uri(const char *uri);
|
||||
|
||||
|
||||
/**
|
||||
Helper function to decode a URI.
|
||||
|
||||
The returned string must be freed by the caller.
|
||||
|
||||
@param uri an encoded URI
|
||||
@return a newly allocated unencoded URI
|
||||
*/
|
||||
char *evhttp_decode_uri(const char *uri);
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to parse out arguments in a query.
|
||||
* The arguments are separated by key and value.
|
||||
* URI should already be decoded.
|
||||
*/
|
||||
void evhttp_parse_query(const char *uri, struct evkeyvalq *);
|
||||
|
||||
|
||||
/**
|
||||
* Escape HTML character entities in a string.
|
||||
*
|
||||
* Replaces <, >, ", ' and & with <, >, ",
|
||||
* ' and & correspondingly.
|
||||
*
|
||||
* The returned string needs to be freed by the caller.
|
||||
*
|
||||
* @param html an unescaped HTML string
|
||||
* @return an escaped HTML string
|
||||
*/
|
||||
char *evhttp_htmlescape(const char *html);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVHTTP_H_ */
|
||||
517
extra/libevent/evport.c
Normal file
517
extra/libevent/evport.c
Normal file
@@ -0,0 +1,517 @@
|
||||
/*
|
||||
* Submitted by David Pacheco (dp.spambait@gmail.com)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Sun Microsystems. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* evport.c: event backend using Solaris 10 event ports. See port_create(3C).
|
||||
* This implementation is loosely modeled after the one used for select(2) (in
|
||||
* select.c).
|
||||
*
|
||||
* The outstanding events are tracked in a data structure called evport_data.
|
||||
* Each entry in the ed_fds array corresponds to a file descriptor, and contains
|
||||
* pointers to the read and write events that correspond to that fd. (That is,
|
||||
* when the file is readable, the "read" event should handle it, etc.)
|
||||
*
|
||||
* evport_add and evport_del update this data structure. evport_dispatch uses it
|
||||
* to determine where to callback when an event occurs (which it gets from
|
||||
* port_getn).
|
||||
*
|
||||
* Helper functions are used: grow() grows the file descriptor array as
|
||||
* necessary when large fd's come in. reassociate() takes care of maintaining
|
||||
* the proper file-descriptor/event-port associations.
|
||||
*
|
||||
* As in the select(2) implementation, signals are handled by evsignal.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVENT_PORTS
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
#include <sys/queue.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <port.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#ifdef CHECK_INVARIANTS
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "log.h"
|
||||
#include "evsignal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Default value for ed_nevents, which is the maximum file descriptor number we
|
||||
* can handle. If an event comes in for a file descriptor F > nevents, we will
|
||||
* grow the array of file descriptors, doubling its size.
|
||||
*/
|
||||
#define DEFAULT_NFDS 16
|
||||
|
||||
|
||||
/*
|
||||
* EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
|
||||
* any particular call. You can speed things up by increasing this, but it will
|
||||
* (obviously) require more memory.
|
||||
*/
|
||||
#define EVENTS_PER_GETN 8
|
||||
|
||||
/*
|
||||
* Per-file-descriptor information about what events we're subscribed to. These
|
||||
* fields are NULL if no event is subscribed to either of them.
|
||||
*/
|
||||
|
||||
struct fd_info {
|
||||
struct event* fdi_revt; /* the event responsible for the "read" */
|
||||
struct event* fdi_wevt; /* the event responsible for the "write" */
|
||||
};
|
||||
|
||||
#define FDI_HAS_READ(fdi) ((fdi)->fdi_revt != NULL)
|
||||
#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL)
|
||||
#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
|
||||
#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
|
||||
(FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
|
||||
|
||||
struct evport_data {
|
||||
int ed_port; /* event port for system events */
|
||||
int ed_nevents; /* number of allocated fdi's */
|
||||
struct fd_info *ed_fds; /* allocated fdi table */
|
||||
/* fdi's that we need to reassoc */
|
||||
int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
|
||||
};
|
||||
|
||||
static void* evport_init (struct event_base *);
|
||||
static int evport_add (void *, struct event *);
|
||||
static int evport_del (void *, struct event *);
|
||||
static int evport_dispatch (struct event_base *, void *, struct timeval *);
|
||||
static void evport_dealloc (struct event_base *, void *);
|
||||
|
||||
const struct eventop evportops = {
|
||||
"event ports",
|
||||
evport_init,
|
||||
evport_add,
|
||||
evport_del,
|
||||
evport_dispatch,
|
||||
evport_dealloc,
|
||||
1 /* need reinit */
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the event port implementation.
|
||||
*/
|
||||
|
||||
static void*
|
||||
evport_init(struct event_base *base)
|
||||
{
|
||||
struct evport_data *evpd;
|
||||
int i;
|
||||
/*
|
||||
* Disable event ports when this environment variable is set
|
||||
*/
|
||||
if (getenv("EVENT_NOEVPORT"))
|
||||
return (NULL);
|
||||
|
||||
if (!(evpd = calloc(1, sizeof(struct evport_data))))
|
||||
return (NULL);
|
||||
|
||||
if ((evpd->ed_port = port_create()) == -1) {
|
||||
free(evpd);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize file descriptor structure
|
||||
*/
|
||||
evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info));
|
||||
if (evpd->ed_fds == NULL) {
|
||||
close(evpd->ed_port);
|
||||
free(evpd);
|
||||
return (NULL);
|
||||
}
|
||||
evpd->ed_nevents = DEFAULT_NFDS;
|
||||
for (i = 0; i < EVENTS_PER_GETN; i++)
|
||||
evpd->ed_pending[i] = -1;
|
||||
|
||||
evsignal_init(base);
|
||||
|
||||
return (evpd);
|
||||
}
|
||||
|
||||
#ifdef CHECK_INVARIANTS
|
||||
/*
|
||||
* Checks some basic properties about the evport_data structure. Because it
|
||||
* checks all file descriptors, this function can be expensive when the maximum
|
||||
* file descriptor ever used is rather large.
|
||||
*/
|
||||
|
||||
static void
|
||||
check_evportop(struct evport_data *evpd)
|
||||
{
|
||||
assert(evpd);
|
||||
assert(evpd->ed_nevents > 0);
|
||||
assert(evpd->ed_port > 0);
|
||||
assert(evpd->ed_fds > 0);
|
||||
|
||||
/*
|
||||
* Verify the integrity of the fd_info struct as well as the events to
|
||||
* which it points (at least, that they're valid references and correct
|
||||
* for their position in the structure).
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < evpd->ed_nevents; ++i) {
|
||||
struct event *ev;
|
||||
struct fd_info *fdi;
|
||||
|
||||
fdi = &evpd->ed_fds[i];
|
||||
if ((ev = fdi->fdi_revt) != NULL) {
|
||||
assert(ev->ev_fd == i);
|
||||
}
|
||||
if ((ev = fdi->fdi_wevt) != NULL) {
|
||||
assert(ev->ev_fd == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies very basic integrity of a given port_event.
|
||||
*/
|
||||
static void
|
||||
check_event(port_event_t* pevt)
|
||||
{
|
||||
/*
|
||||
* We've only registered for PORT_SOURCE_FD events. The only
|
||||
* other thing we can legitimately receive is PORT_SOURCE_ALERT,
|
||||
* but since we're not using port_alert either, we can assume
|
||||
* PORT_SOURCE_FD.
|
||||
*/
|
||||
assert(pevt->portev_source == PORT_SOURCE_FD);
|
||||
assert(pevt->portev_user == NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
#define check_evportop(epop)
|
||||
#define check_event(pevt)
|
||||
#endif /* CHECK_INVARIANTS */
|
||||
|
||||
/*
|
||||
* Doubles the size of the allocated file descriptor array.
|
||||
*/
|
||||
static int
|
||||
grow(struct evport_data *epdp, int factor)
|
||||
{
|
||||
struct fd_info *tmp;
|
||||
int oldsize = epdp->ed_nevents;
|
||||
int newsize = factor * oldsize;
|
||||
assert(factor > 1);
|
||||
|
||||
check_evportop(epdp);
|
||||
|
||||
tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
|
||||
if (NULL == tmp)
|
||||
return -1;
|
||||
epdp->ed_fds = tmp;
|
||||
memset((char*) (epdp->ed_fds + oldsize), 0,
|
||||
(newsize - oldsize)*sizeof(struct fd_info));
|
||||
epdp->ed_nevents = newsize;
|
||||
|
||||
check_evportop(epdp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (Re)associates the given file descriptor with the event port. The OS events
|
||||
* are specified (implicitly) from the fd_info struct.
|
||||
*/
|
||||
static int
|
||||
reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
|
||||
{
|
||||
int sysevents = FDI_TO_SYSEVENTS(fdip);
|
||||
|
||||
if (sysevents != 0) {
|
||||
if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
|
||||
fd, sysevents, NULL) == -1) {
|
||||
event_warn("port_associate");
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
check_evportop(epdp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main event loop - polls port_getn for some number of events, and processes
|
||||
* them.
|
||||
*/
|
||||
|
||||
static int
|
||||
evport_dispatch(struct event_base *base, void *arg, struct timeval *tv)
|
||||
{
|
||||
int i, res;
|
||||
struct evport_data *epdp = arg;
|
||||
port_event_t pevtlist[EVENTS_PER_GETN];
|
||||
|
||||
/*
|
||||
* port_getn will block until it has at least nevents events. It will
|
||||
* also return how many it's given us (which may be more than we asked
|
||||
* for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
|
||||
* nevents.
|
||||
*/
|
||||
int nevents = 1;
|
||||
|
||||
/*
|
||||
* We have to convert a struct timeval to a struct timespec
|
||||
* (only difference is nanoseconds vs. microseconds). If no time-based
|
||||
* events are active, we should wait for I/O (and tv == NULL).
|
||||
*/
|
||||
struct timespec ts;
|
||||
struct timespec *ts_p = NULL;
|
||||
if (tv != NULL) {
|
||||
ts.tv_sec = tv->tv_sec;
|
||||
ts.tv_nsec = tv->tv_usec * 1000;
|
||||
ts_p = &ts;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before doing anything else, we need to reassociate the events we hit
|
||||
* last time which need reassociation. See comment at the end of the
|
||||
* loop below.
|
||||
*/
|
||||
for (i = 0; i < EVENTS_PER_GETN; ++i) {
|
||||
struct fd_info *fdi = NULL;
|
||||
if (epdp->ed_pending[i] != -1) {
|
||||
fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
|
||||
}
|
||||
|
||||
if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
|
||||
int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd :
|
||||
fdi->fdi_wevt->ev_fd;
|
||||
reassociate(epdp, fdi, fd);
|
||||
epdp->ed_pending[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN,
|
||||
(unsigned int *) &nevents, ts_p)) == -1) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
evsignal_process(base);
|
||||
return (0);
|
||||
} else if (errno == ETIME) {
|
||||
if (nevents == 0)
|
||||
return (0);
|
||||
} else {
|
||||
event_warn("port_getn");
|
||||
return (-1);
|
||||
}
|
||||
} else if (base->sig.evsignal_caught) {
|
||||
evsignal_process(base);
|
||||
}
|
||||
|
||||
event_debug(("%s: port_getn reports %d events", __func__, nevents));
|
||||
|
||||
for (i = 0; i < nevents; ++i) {
|
||||
struct event *ev;
|
||||
struct fd_info *fdi;
|
||||
port_event_t *pevt = &pevtlist[i];
|
||||
int fd = (int) pevt->portev_object;
|
||||
|
||||
check_evportop(epdp);
|
||||
check_event(pevt);
|
||||
epdp->ed_pending[i] = fd;
|
||||
|
||||
/*
|
||||
* Figure out what kind of event it was
|
||||
* (because we have to pass this to the callback)
|
||||
*/
|
||||
res = 0;
|
||||
if (pevt->portev_events & POLLIN)
|
||||
res |= EV_READ;
|
||||
if (pevt->portev_events & POLLOUT)
|
||||
res |= EV_WRITE;
|
||||
|
||||
assert(epdp->ed_nevents > fd);
|
||||
fdi = &(epdp->ed_fds[fd]);
|
||||
|
||||
/*
|
||||
* We now check for each of the possible events (READ
|
||||
* or WRITE). Then, we activate the event (which will
|
||||
* cause its callback to be executed).
|
||||
*/
|
||||
|
||||
if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) {
|
||||
event_active(ev, res, 1);
|
||||
}
|
||||
|
||||
if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) {
|
||||
event_active(ev, res, 1);
|
||||
}
|
||||
} /* end of all events gotten */
|
||||
|
||||
check_evportop(epdp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds the given event (so that you will be notified when it happens via
|
||||
* the callback function).
|
||||
*/
|
||||
|
||||
static int
|
||||
evport_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct evport_data *evpd = arg;
|
||||
struct fd_info *fdi;
|
||||
int factor;
|
||||
|
||||
check_evportop(evpd);
|
||||
|
||||
/*
|
||||
* Delegate, if it's not ours to handle.
|
||||
*/
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_add(ev));
|
||||
|
||||
/*
|
||||
* If necessary, grow the file descriptor info table
|
||||
*/
|
||||
|
||||
factor = 1;
|
||||
while (ev->ev_fd >= factor * evpd->ed_nevents)
|
||||
factor *= 2;
|
||||
|
||||
if (factor > 1) {
|
||||
if (-1 == grow(evpd, factor)) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
fdi = &evpd->ed_fds[ev->ev_fd];
|
||||
if (ev->ev_events & EV_READ)
|
||||
fdi->fdi_revt = ev;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
fdi->fdi_wevt = ev;
|
||||
|
||||
return reassociate(evpd, fdi, ev->ev_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes the given event from the list of events to wait for.
|
||||
*/
|
||||
|
||||
static int
|
||||
evport_del(void *arg, struct event *ev)
|
||||
{
|
||||
struct evport_data *evpd = arg;
|
||||
struct fd_info *fdi;
|
||||
int i;
|
||||
int associated = 1;
|
||||
|
||||
check_evportop(evpd);
|
||||
|
||||
/*
|
||||
* Delegate, if it's not ours to handle
|
||||
*/
|
||||
if (ev->ev_events & EV_SIGNAL) {
|
||||
return (evsignal_del(ev));
|
||||
}
|
||||
|
||||
if (evpd->ed_nevents < ev->ev_fd) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < EVENTS_PER_GETN; ++i) {
|
||||
if (evpd->ed_pending[i] == ev->ev_fd) {
|
||||
associated = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fdi = &evpd->ed_fds[ev->ev_fd];
|
||||
if (ev->ev_events & EV_READ)
|
||||
fdi->fdi_revt = NULL;
|
||||
if (ev->ev_events & EV_WRITE)
|
||||
fdi->fdi_wevt = NULL;
|
||||
|
||||
if (associated) {
|
||||
if (!FDI_HAS_EVENTS(fdi) &&
|
||||
port_dissociate(evpd->ed_port, PORT_SOURCE_FD,
|
||||
ev->ev_fd) == -1) {
|
||||
/*
|
||||
* Ignre EBADFD error the fd could have been closed
|
||||
* before event_del() was called.
|
||||
*/
|
||||
if (errno != EBADFD) {
|
||||
event_warn("port_dissociate");
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
if (FDI_HAS_EVENTS(fdi)) {
|
||||
return (reassociate(evpd, fdi, ev->ev_fd));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fdi->fdi_revt == NULL && fdi->fdi_wevt == NULL) {
|
||||
evpd->ed_pending[i] = -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
evport_dealloc(struct event_base *base, void *arg)
|
||||
{
|
||||
struct evport_data *evpd = arg;
|
||||
|
||||
evsignal_dealloc(base);
|
||||
|
||||
close(evpd->ed_port);
|
||||
|
||||
if (evpd->ed_fds)
|
||||
free(evpd->ed_fds);
|
||||
free(evpd);
|
||||
}
|
||||
|
||||
#endif /* HAVE_EVENT_PORTS */
|
||||
87
extra/libevent/evrpc-internal.h
Normal file
87
extra/libevent/evrpc-internal.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVRPC_INTERNAL_H_
|
||||
#define _EVRPC_INTERNAL_H_
|
||||
|
||||
#include "http-internal.h"
|
||||
|
||||
struct evrpc;
|
||||
|
||||
#define EVRPC_URI_PREFIX "/.rpc."
|
||||
|
||||
struct evrpc_hook {
|
||||
TAILQ_ENTRY(evrpc_hook) (next);
|
||||
|
||||
/* returns -1; if the rpc should be aborted, is allowed to rewrite */
|
||||
int (*process)(struct evhttp_request *, struct evbuffer *, void *);
|
||||
void *process_arg;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(evrpc_hook_list, evrpc_hook);
|
||||
|
||||
/*
|
||||
* this is shared between the base and the pool, so that we can reuse
|
||||
* the hook adding functions; we alias both evrpc_pool and evrpc_base
|
||||
* to this common structure.
|
||||
*/
|
||||
struct _evrpc_hooks {
|
||||
/* hooks for processing outbound and inbound rpcs */
|
||||
struct evrpc_hook_list in_hooks;
|
||||
struct evrpc_hook_list out_hooks;
|
||||
};
|
||||
|
||||
#define input_hooks common.in_hooks
|
||||
#define output_hooks common.out_hooks
|
||||
|
||||
struct evrpc_base {
|
||||
struct _evrpc_hooks common;
|
||||
|
||||
/* the HTTP server under which we register our RPC calls */
|
||||
struct evhttp* http_server;
|
||||
|
||||
/* a list of all RPCs registered with us */
|
||||
TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs;
|
||||
};
|
||||
|
||||
struct evrpc_req_generic;
|
||||
void evrpc_reqstate_free(struct evrpc_req_generic* rpc_state);
|
||||
|
||||
/* A pool for holding evhttp_connection objects */
|
||||
struct evrpc_pool {
|
||||
struct _evrpc_hooks common;
|
||||
|
||||
struct event_base *base;
|
||||
|
||||
struct evconq connections;
|
||||
|
||||
int timeout;
|
||||
|
||||
TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) requests;
|
||||
};
|
||||
|
||||
|
||||
#endif /* _EVRPC_INTERNAL_H_ */
|
||||
658
extra/libevent/evrpc.c
Normal file
658
extra/libevent/evrpc.c
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "event.h"
|
||||
#include "evrpc.h"
|
||||
#include "evrpc-internal.h"
|
||||
#include "evhttp.h"
|
||||
#include "evutil.h"
|
||||
#include "log.h"
|
||||
|
||||
struct evrpc_base *
|
||||
evrpc_init(struct evhttp *http_server)
|
||||
{
|
||||
struct evrpc_base* base = calloc(1, sizeof(struct evrpc_base));
|
||||
if (base == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* we rely on the tagging sub system */
|
||||
evtag_init();
|
||||
|
||||
TAILQ_INIT(&base->registered_rpcs);
|
||||
TAILQ_INIT(&base->input_hooks);
|
||||
TAILQ_INIT(&base->output_hooks);
|
||||
base->http_server = http_server;
|
||||
|
||||
return (base);
|
||||
}
|
||||
|
||||
void
|
||||
evrpc_free(struct evrpc_base *base)
|
||||
{
|
||||
struct evrpc *rpc;
|
||||
struct evrpc_hook *hook;
|
||||
|
||||
while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
|
||||
assert(evrpc_unregister_rpc(base, rpc->uri));
|
||||
}
|
||||
while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
|
||||
assert(evrpc_remove_hook(base, INPUT, hook));
|
||||
}
|
||||
while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
|
||||
assert(evrpc_remove_hook(base, OUTPUT, hook));
|
||||
}
|
||||
free(base);
|
||||
}
|
||||
|
||||
void *
|
||||
evrpc_add_hook(void *vbase,
|
||||
enum EVRPC_HOOK_TYPE hook_type,
|
||||
int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
|
||||
void *cb_arg)
|
||||
{
|
||||
struct _evrpc_hooks *base = vbase;
|
||||
struct evrpc_hook_list *head = NULL;
|
||||
struct evrpc_hook *hook = NULL;
|
||||
switch (hook_type) {
|
||||
case INPUT:
|
||||
head = &base->in_hooks;
|
||||
break;
|
||||
case OUTPUT:
|
||||
head = &base->out_hooks;
|
||||
break;
|
||||
default:
|
||||
assert(hook_type == INPUT || hook_type == OUTPUT);
|
||||
}
|
||||
|
||||
hook = calloc(1, sizeof(struct evrpc_hook));
|
||||
assert(hook != NULL);
|
||||
|
||||
hook->process = cb;
|
||||
hook->process_arg = cb_arg;
|
||||
TAILQ_INSERT_TAIL(head, hook, next);
|
||||
|
||||
return (hook);
|
||||
}
|
||||
|
||||
static int
|
||||
evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
|
||||
{
|
||||
struct evrpc_hook *hook = NULL;
|
||||
TAILQ_FOREACH(hook, head, next) {
|
||||
if (hook == handle) {
|
||||
TAILQ_REMOVE(head, hook, next);
|
||||
free(hook);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove the hook specified by the handle
|
||||
*/
|
||||
|
||||
int
|
||||
evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
|
||||
{
|
||||
struct _evrpc_hooks *base = vbase;
|
||||
struct evrpc_hook_list *head = NULL;
|
||||
switch (hook_type) {
|
||||
case INPUT:
|
||||
head = &base->in_hooks;
|
||||
break;
|
||||
case OUTPUT:
|
||||
head = &base->out_hooks;
|
||||
break;
|
||||
default:
|
||||
assert(hook_type == INPUT || hook_type == OUTPUT);
|
||||
}
|
||||
|
||||
return (evrpc_remove_hook_internal(head, handle));
|
||||
}
|
||||
|
||||
static int
|
||||
evrpc_process_hooks(struct evrpc_hook_list *head,
|
||||
struct evhttp_request *req, struct evbuffer *evbuf)
|
||||
{
|
||||
struct evrpc_hook *hook;
|
||||
TAILQ_FOREACH(hook, head, next) {
|
||||
if (hook->process(req, evbuf, hook->process_arg) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void evrpc_pool_schedule(struct evrpc_pool *pool);
|
||||
static void evrpc_request_cb(struct evhttp_request *, void *);
|
||||
void evrpc_request_done(struct evrpc_req_generic*);
|
||||
|
||||
/*
|
||||
* Registers a new RPC with the HTTP server. The evrpc object is expected
|
||||
* to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
|
||||
* calls this function.
|
||||
*/
|
||||
|
||||
static char *
|
||||
evrpc_construct_uri(const char *uri)
|
||||
{
|
||||
char *constructed_uri;
|
||||
int constructed_uri_len;
|
||||
|
||||
constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
|
||||
if ((constructed_uri = malloc(constructed_uri_len)) == NULL)
|
||||
event_err(1, "%s: failed to register rpc at %s",
|
||||
__func__, uri);
|
||||
memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
|
||||
memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
|
||||
constructed_uri[constructed_uri_len - 1] = '\0';
|
||||
|
||||
return (constructed_uri);
|
||||
}
|
||||
|
||||
int
|
||||
evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
|
||||
void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
|
||||
{
|
||||
char *constructed_uri = evrpc_construct_uri(rpc->uri);
|
||||
|
||||
rpc->base = base;
|
||||
rpc->cb = cb;
|
||||
rpc->cb_arg = cb_arg;
|
||||
|
||||
TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
|
||||
|
||||
evhttp_set_cb(base->http_server,
|
||||
constructed_uri,
|
||||
evrpc_request_cb,
|
||||
rpc);
|
||||
|
||||
free(constructed_uri);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
|
||||
{
|
||||
char *registered_uri = NULL;
|
||||
struct evrpc *rpc;
|
||||
|
||||
/* find the right rpc; linear search might be slow */
|
||||
TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
|
||||
if (strcmp(rpc->uri, name) == 0)
|
||||
break;
|
||||
}
|
||||
if (rpc == NULL) {
|
||||
/* We did not find an RPC with this name */
|
||||
return (-1);
|
||||
}
|
||||
TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
|
||||
|
||||
free((char *)rpc->uri);
|
||||
free(rpc);
|
||||
|
||||
registered_uri = evrpc_construct_uri(name);
|
||||
|
||||
/* remove the http server callback */
|
||||
assert(evhttp_del_cb(base->http_server, registered_uri) == 0);
|
||||
|
||||
free(registered_uri);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
evrpc_request_cb(struct evhttp_request *req, void *arg)
|
||||
{
|
||||
struct evrpc *rpc = arg;
|
||||
struct evrpc_req_generic *rpc_state = NULL;
|
||||
|
||||
/* let's verify the outside parameters */
|
||||
if (req->type != EVHTTP_REQ_POST ||
|
||||
EVBUFFER_LENGTH(req->input_buffer) <= 0)
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* we might want to allow hooks to suspend the processing,
|
||||
* but at the moment, we assume that they just act as simple
|
||||
* filters.
|
||||
*/
|
||||
if (evrpc_process_hooks(&rpc->base->input_hooks,
|
||||
req, req->input_buffer) == -1)
|
||||
goto error;
|
||||
|
||||
rpc_state = calloc(1, sizeof(struct evrpc_req_generic));
|
||||
if (rpc_state == NULL)
|
||||
goto error;
|
||||
|
||||
/* let's check that we can parse the request */
|
||||
rpc_state->request = rpc->request_new();
|
||||
if (rpc_state->request == NULL)
|
||||
goto error;
|
||||
|
||||
rpc_state->rpc = rpc;
|
||||
|
||||
if (rpc->request_unmarshal(
|
||||
rpc_state->request, req->input_buffer) == -1) {
|
||||
/* we failed to parse the request; that's a bummer */
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* at this point, we have a well formed request, prepare the reply */
|
||||
|
||||
rpc_state->reply = rpc->reply_new();
|
||||
if (rpc_state->reply == NULL)
|
||||
goto error;
|
||||
|
||||
rpc_state->http_req = req;
|
||||
rpc_state->done = evrpc_request_done;
|
||||
|
||||
/* give the rpc to the user; they can deal with it */
|
||||
rpc->cb(rpc_state, rpc->cb_arg);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
evrpc_reqstate_free(rpc_state);
|
||||
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
evrpc_reqstate_free(struct evrpc_req_generic* rpc_state)
|
||||
{
|
||||
/* clean up all memory */
|
||||
if (rpc_state != NULL) {
|
||||
struct evrpc *rpc = rpc_state->rpc;
|
||||
|
||||
if (rpc_state->request != NULL)
|
||||
rpc->request_free(rpc_state->request);
|
||||
if (rpc_state->reply != NULL)
|
||||
rpc->reply_free(rpc_state->reply);
|
||||
free(rpc_state);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
evrpc_request_done(struct evrpc_req_generic* rpc_state)
|
||||
{
|
||||
struct evhttp_request *req = rpc_state->http_req;
|
||||
struct evrpc *rpc = rpc_state->rpc;
|
||||
struct evbuffer* data = NULL;
|
||||
|
||||
if (rpc->reply_complete(rpc_state->reply) == -1) {
|
||||
/* the reply was not completely filled in. error out */
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((data = evbuffer_new()) == NULL) {
|
||||
/* out of memory */
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* serialize the reply */
|
||||
rpc->reply_marshal(data, rpc_state->reply);
|
||||
|
||||
/* do hook based tweaks to the request */
|
||||
if (evrpc_process_hooks(&rpc->base->output_hooks,
|
||||
req, data) == -1)
|
||||
goto error;
|
||||
|
||||
/* on success, we are going to transmit marshaled binary data */
|
||||
if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
|
||||
evhttp_add_header(req->output_headers,
|
||||
"Content-Type", "application/octet-stream");
|
||||
}
|
||||
|
||||
evhttp_send_reply(req, HTTP_OK, "OK", data);
|
||||
|
||||
evbuffer_free(data);
|
||||
|
||||
evrpc_reqstate_free(rpc_state);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
if (data != NULL)
|
||||
evbuffer_free(data);
|
||||
evrpc_reqstate_free(rpc_state);
|
||||
evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Client implementation of RPC site */
|
||||
|
||||
static int evrpc_schedule_request(struct evhttp_connection *connection,
|
||||
struct evrpc_request_wrapper *ctx);
|
||||
|
||||
struct evrpc_pool *
|
||||
evrpc_pool_new(struct event_base *base)
|
||||
{
|
||||
struct evrpc_pool *pool = calloc(1, sizeof(struct evrpc_pool));
|
||||
if (pool == NULL)
|
||||
return (NULL);
|
||||
|
||||
TAILQ_INIT(&pool->connections);
|
||||
TAILQ_INIT(&pool->requests);
|
||||
|
||||
TAILQ_INIT(&pool->input_hooks);
|
||||
TAILQ_INIT(&pool->output_hooks);
|
||||
|
||||
pool->base = base;
|
||||
pool->timeout = -1;
|
||||
|
||||
return (pool);
|
||||
}
|
||||
|
||||
static void
|
||||
evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
|
||||
{
|
||||
free(request->name);
|
||||
free(request);
|
||||
}
|
||||
|
||||
void
|
||||
evrpc_pool_free(struct evrpc_pool *pool)
|
||||
{
|
||||
struct evhttp_connection *connection;
|
||||
struct evrpc_request_wrapper *request;
|
||||
struct evrpc_hook *hook;
|
||||
|
||||
while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
|
||||
TAILQ_REMOVE(&pool->requests, request, next);
|
||||
/* if this gets more complicated we need our own function */
|
||||
evrpc_request_wrapper_free(request);
|
||||
}
|
||||
|
||||
while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
|
||||
TAILQ_REMOVE(&pool->connections, connection, next);
|
||||
evhttp_connection_free(connection);
|
||||
}
|
||||
|
||||
while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
|
||||
assert(evrpc_remove_hook(pool, INPUT, hook));
|
||||
}
|
||||
|
||||
while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
|
||||
assert(evrpc_remove_hook(pool, OUTPUT, hook));
|
||||
}
|
||||
|
||||
free(pool);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a connection to the RPC pool. A request scheduled on the pool
|
||||
* may use any available connection.
|
||||
*/
|
||||
|
||||
void
|
||||
evrpc_pool_add_connection(struct evrpc_pool *pool,
|
||||
struct evhttp_connection *connection) {
|
||||
assert(connection->http_server == NULL);
|
||||
TAILQ_INSERT_TAIL(&pool->connections, connection, next);
|
||||
|
||||
/*
|
||||
* associate an event base with this connection
|
||||
*/
|
||||
if (pool->base != NULL)
|
||||
evhttp_connection_set_base(connection, pool->base);
|
||||
|
||||
/*
|
||||
* unless a timeout was specifically set for a connection,
|
||||
* the connection inherits the timeout from the pool.
|
||||
*/
|
||||
if (connection->timeout == -1)
|
||||
connection->timeout = pool->timeout;
|
||||
|
||||
/*
|
||||
* if we have any requests pending, schedule them with the new
|
||||
* connections.
|
||||
*/
|
||||
|
||||
if (TAILQ_FIRST(&pool->requests) != NULL) {
|
||||
struct evrpc_request_wrapper *request =
|
||||
TAILQ_FIRST(&pool->requests);
|
||||
TAILQ_REMOVE(&pool->requests, request, next);
|
||||
evrpc_schedule_request(connection, request);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
|
||||
{
|
||||
struct evhttp_connection *evcon;
|
||||
TAILQ_FOREACH(evcon, &pool->connections, next) {
|
||||
evcon->timeout = timeout_in_secs;
|
||||
}
|
||||
pool->timeout = timeout_in_secs;
|
||||
}
|
||||
|
||||
|
||||
static void evrpc_reply_done(struct evhttp_request *, void *);
|
||||
static void evrpc_request_timeout(int, short, void *);
|
||||
|
||||
/*
|
||||
* Finds a connection object associated with the pool that is currently
|
||||
* idle and can be used to make a request.
|
||||
*/
|
||||
static struct evhttp_connection *
|
||||
evrpc_pool_find_connection(struct evrpc_pool *pool)
|
||||
{
|
||||
struct evhttp_connection *connection;
|
||||
TAILQ_FOREACH(connection, &pool->connections, next) {
|
||||
if (TAILQ_FIRST(&connection->requests) == NULL)
|
||||
return (connection);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume that the ctx is no longer queued on the pool.
|
||||
*/
|
||||
static int
|
||||
evrpc_schedule_request(struct evhttp_connection *connection,
|
||||
struct evrpc_request_wrapper *ctx)
|
||||
{
|
||||
struct evhttp_request *req = NULL;
|
||||
struct evrpc_pool *pool = ctx->pool;
|
||||
struct evrpc_status status;
|
||||
char *uri = NULL;
|
||||
int res = 0;
|
||||
|
||||
if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
|
||||
goto error;
|
||||
|
||||
/* serialize the request data into the output buffer */
|
||||
ctx->request_marshal(req->output_buffer, ctx->request);
|
||||
|
||||
uri = evrpc_construct_uri(ctx->name);
|
||||
if (uri == NULL)
|
||||
goto error;
|
||||
|
||||
/* we need to know the connection that we might have to abort */
|
||||
ctx->evcon = connection;
|
||||
|
||||
/* apply hooks to the outgoing request */
|
||||
if (evrpc_process_hooks(&pool->output_hooks,
|
||||
req, req->output_buffer) == -1)
|
||||
goto error;
|
||||
|
||||
if (pool->timeout > 0) {
|
||||
/*
|
||||
* a timeout after which the whole rpc is going to be aborted.
|
||||
*/
|
||||
struct timeval tv;
|
||||
evutil_timerclear(&tv);
|
||||
tv.tv_sec = pool->timeout;
|
||||
evtimer_add(&ctx->ev_timeout, &tv);
|
||||
}
|
||||
|
||||
/* start the request over the connection */
|
||||
res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
|
||||
free(uri);
|
||||
|
||||
if (res == -1)
|
||||
goto error;
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
memset(&status, 0, sizeof(status));
|
||||
status.error = EVRPC_STATUS_ERR_UNSTARTED;
|
||||
(*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
|
||||
evrpc_request_wrapper_free(ctx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
evrpc_make_request(struct evrpc_request_wrapper *ctx)
|
||||
{
|
||||
struct evrpc_pool *pool = ctx->pool;
|
||||
|
||||
/* initialize the event structure for this rpc */
|
||||
evtimer_set(&ctx->ev_timeout, evrpc_request_timeout, ctx);
|
||||
if (pool->base != NULL)
|
||||
event_base_set(pool->base, &ctx->ev_timeout);
|
||||
|
||||
/* we better have some available connections on the pool */
|
||||
assert(TAILQ_FIRST(&pool->connections) != NULL);
|
||||
|
||||
/*
|
||||
* if no connection is available, we queue the request on the pool,
|
||||
* the next time a connection is empty, the rpc will be send on that.
|
||||
*/
|
||||
TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
|
||||
|
||||
evrpc_pool_schedule(pool);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
evrpc_reply_done(struct evhttp_request *req, void *arg)
|
||||
{
|
||||
struct evrpc_request_wrapper *ctx = arg;
|
||||
struct evrpc_pool *pool = ctx->pool;
|
||||
struct evrpc_status status;
|
||||
int res = -1;
|
||||
|
||||
/* cancel any timeout we might have scheduled */
|
||||
event_del(&ctx->ev_timeout);
|
||||
|
||||
memset(&status, 0, sizeof(status));
|
||||
status.http_req = req;
|
||||
|
||||
/* we need to get the reply now */
|
||||
if (req != NULL) {
|
||||
/* apply hooks to the incoming request */
|
||||
if (evrpc_process_hooks(&pool->input_hooks,
|
||||
req, req->input_buffer) == -1) {
|
||||
status.error = EVRPC_STATUS_ERR_HOOKABORTED;
|
||||
res = -1;
|
||||
} else {
|
||||
res = ctx->reply_unmarshal(ctx->reply,
|
||||
req->input_buffer);
|
||||
if (res == -1) {
|
||||
status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status.error = EVRPC_STATUS_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
if (res == -1) {
|
||||
/* clear everything that we might have written previously */
|
||||
ctx->reply_clear(ctx->reply);
|
||||
}
|
||||
|
||||
(*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
|
||||
|
||||
evrpc_request_wrapper_free(ctx);
|
||||
|
||||
/* the http layer owns the request structure */
|
||||
|
||||
/* see if we can schedule another request */
|
||||
evrpc_pool_schedule(pool);
|
||||
}
|
||||
|
||||
static void
|
||||
evrpc_pool_schedule(struct evrpc_pool *pool)
|
||||
{
|
||||
struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
|
||||
struct evhttp_connection *evcon;
|
||||
|
||||
/* if no requests are pending, we have no work */
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
|
||||
TAILQ_REMOVE(&pool->requests, ctx, next);
|
||||
evrpc_schedule_request(evcon, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
evrpc_request_timeout(int fd, short what, void *arg)
|
||||
{
|
||||
struct evrpc_request_wrapper *ctx = arg;
|
||||
struct evhttp_connection *evcon = ctx->evcon;
|
||||
assert(evcon != NULL);
|
||||
|
||||
evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
|
||||
}
|
||||
477
extra/libevent/evrpc.h
Normal file
477
extra/libevent/evrpc.h
Normal file
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVRPC_H_
|
||||
#define _EVRPC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @file evrpc.h
|
||||
*
|
||||
* This header files provides basic support for an RPC server and client.
|
||||
*
|
||||
* To support RPCs in a server, every supported RPC command needs to be
|
||||
* defined and registered.
|
||||
*
|
||||
* EVRPC_HEADER(SendCommand, Request, Reply);
|
||||
*
|
||||
* SendCommand is the name of the RPC command.
|
||||
* Request is the name of a structure generated by event_rpcgen.py.
|
||||
* It contains all parameters relating to the SendCommand RPC. The
|
||||
* server needs to fill in the Reply structure.
|
||||
* Reply is the name of a structure generated by event_rpcgen.py. It
|
||||
* contains the answer to the RPC.
|
||||
*
|
||||
* To register an RPC with an HTTP server, you need to first create an RPC
|
||||
* base with:
|
||||
*
|
||||
* struct evrpc_base *base = evrpc_init(http);
|
||||
*
|
||||
* A specific RPC can then be registered with
|
||||
*
|
||||
* EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg);
|
||||
*
|
||||
* when the server receives an appropriately formatted RPC, the user callback
|
||||
* is invokved. The callback needs to fill in the reply structure.
|
||||
*
|
||||
* void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
|
||||
*
|
||||
* To send the reply, call EVRPC_REQUEST_DONE(rpc);
|
||||
*
|
||||
* See the regression test for an example.
|
||||
*/
|
||||
|
||||
struct evbuffer;
|
||||
struct event_base;
|
||||
struct evrpc_req_generic;
|
||||
|
||||
/* Encapsulates a request */
|
||||
struct evrpc {
|
||||
TAILQ_ENTRY(evrpc) next;
|
||||
|
||||
/* the URI at which the request handler lives */
|
||||
const char* uri;
|
||||
|
||||
/* creates a new request structure */
|
||||
void *(*request_new)(void);
|
||||
|
||||
/* frees the request structure */
|
||||
void (*request_free)(void *);
|
||||
|
||||
/* unmarshals the buffer into the proper request structure */
|
||||
int (*request_unmarshal)(void *, struct evbuffer *);
|
||||
|
||||
/* creates a new reply structure */
|
||||
void *(*reply_new)(void);
|
||||
|
||||
/* creates a new reply structure */
|
||||
void (*reply_free)(void *);
|
||||
|
||||
/* verifies that the reply is valid */
|
||||
int (*reply_complete)(void *);
|
||||
|
||||
/* marshals the reply into a buffer */
|
||||
void (*reply_marshal)(struct evbuffer*, void *);
|
||||
|
||||
/* the callback invoked for each received rpc */
|
||||
void (*cb)(struct evrpc_req_generic *, void *);
|
||||
void *cb_arg;
|
||||
|
||||
/* reference for further configuration */
|
||||
struct evrpc_base *base;
|
||||
};
|
||||
|
||||
/** The type of a specific RPC Message
|
||||
*
|
||||
* @param rpcname the name of the RPC message
|
||||
*/
|
||||
#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
|
||||
|
||||
struct evhttp_request;
|
||||
struct evrpc_status;
|
||||
|
||||
/* We alias the RPC specific structs to this voided one */
|
||||
struct evrpc_req_generic {
|
||||
/* the unmarshaled request object */
|
||||
void *request;
|
||||
|
||||
/* the empty reply object that needs to be filled in */
|
||||
void *reply;
|
||||
|
||||
/*
|
||||
* the static structure for this rpc; that can be used to
|
||||
* automatically unmarshal and marshal the http buffers.
|
||||
*/
|
||||
struct evrpc *rpc;
|
||||
|
||||
/*
|
||||
* the http request structure on which we need to answer.
|
||||
*/
|
||||
struct evhttp_request* http_req;
|
||||
|
||||
/*
|
||||
* callback to reply and finish answering this rpc
|
||||
*/
|
||||
void (*done)(struct evrpc_req_generic* rpc);
|
||||
};
|
||||
|
||||
/** Creates the definitions and prototypes for an RPC
|
||||
*
|
||||
* You need to use EVRPC_HEADER to create structures and function prototypes
|
||||
* needed by the server and client implementation. The structures have to be
|
||||
* defined in an .rpc file and converted to source code via event_rpcgen.py
|
||||
*
|
||||
* @param rpcname the name of the RPC
|
||||
* @param reqstruct the name of the RPC request structure
|
||||
* @param replystruct the name of the RPC reply structure
|
||||
* @see EVRPC_GENERATE()
|
||||
*/
|
||||
#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
|
||||
EVRPC_STRUCT(rpcname) { \
|
||||
struct reqstruct* request; \
|
||||
struct rplystruct* reply; \
|
||||
struct evrpc* rpc; \
|
||||
struct evhttp_request* http_req; \
|
||||
void (*done)(struct evrpc_status *, \
|
||||
struct evrpc* rpc, void *request, void *reply); \
|
||||
}; \
|
||||
int evrpc_send_request_##rpcname(struct evrpc_pool *, \
|
||||
struct reqstruct *, struct rplystruct *, \
|
||||
void (*)(struct evrpc_status *, \
|
||||
struct reqstruct *, struct rplystruct *, void *cbarg), \
|
||||
void *);
|
||||
|
||||
/** Generates the code for receiving and sending an RPC message
|
||||
*
|
||||
* EVRPC_GENERATE is used to create the code corresponding to sending
|
||||
* and receiving a particular RPC message
|
||||
*
|
||||
* @param rpcname the name of the RPC
|
||||
* @param reqstruct the name of the RPC request structure
|
||||
* @param replystruct the name of the RPC reply structure
|
||||
* @see EVRPC_HEADER()
|
||||
*/
|
||||
#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
|
||||
int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
|
||||
struct reqstruct *request, struct rplystruct *reply, \
|
||||
void (*cb)(struct evrpc_status *, \
|
||||
struct reqstruct *, struct rplystruct *, void *cbarg), \
|
||||
void *cbarg) { \
|
||||
struct evrpc_status status; \
|
||||
struct evrpc_request_wrapper *ctx; \
|
||||
ctx = (struct evrpc_request_wrapper *) \
|
||||
malloc(sizeof(struct evrpc_request_wrapper)); \
|
||||
if (ctx == NULL) \
|
||||
goto error; \
|
||||
ctx->pool = pool; \
|
||||
ctx->evcon = NULL; \
|
||||
ctx->name = strdup(#rpcname); \
|
||||
if (ctx->name == NULL) { \
|
||||
free(ctx); \
|
||||
goto error; \
|
||||
} \
|
||||
ctx->cb = (void (*)(struct evrpc_status *, \
|
||||
void *, void *, void *))cb; \
|
||||
ctx->cb_arg = cbarg; \
|
||||
ctx->request = (void *)request; \
|
||||
ctx->reply = (void *)reply; \
|
||||
ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \
|
||||
ctx->reply_clear = (void (*)(void *))rplystruct##_clear; \
|
||||
ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \
|
||||
return (evrpc_make_request(ctx)); \
|
||||
error: \
|
||||
memset(&status, 0, sizeof(status)); \
|
||||
status.error = EVRPC_STATUS_ERR_UNSTARTED; \
|
||||
(*(cb))(&status, request, reply, cbarg); \
|
||||
return (-1); \
|
||||
}
|
||||
|
||||
/** Provides access to the HTTP request object underlying an RPC
|
||||
*
|
||||
* Access to the underlying http object; can be used to look at headers or
|
||||
* for getting the remote ip address
|
||||
*
|
||||
* @param rpc_req the rpc request structure provided to the server callback
|
||||
* @return an struct evhttp_request object that can be inspected for
|
||||
* HTTP headers or sender information.
|
||||
*/
|
||||
#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
|
||||
|
||||
/** Creates the reply to an RPC request
|
||||
*
|
||||
* EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
|
||||
* to have been filled in. The request and reply pointers become invalid
|
||||
* after this call has finished.
|
||||
*
|
||||
* @param rpc_req the rpc request structure provided to the server callback
|
||||
*/
|
||||
#define EVRPC_REQUEST_DONE(rpc_req) do { \
|
||||
struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
|
||||
_req->done(_req); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Takes a request object and fills it in with the right magic */
|
||||
#define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \
|
||||
do { \
|
||||
(rpc)->uri = strdup(#name); \
|
||||
if ((rpc)->uri == NULL) { \
|
||||
fprintf(stderr, "failed to register object\n"); \
|
||||
exit(1); \
|
||||
} \
|
||||
(rpc)->request_new = (void *(*)(void))request##_new; \
|
||||
(rpc)->request_free = (void (*)(void *))request##_free; \
|
||||
(rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
|
||||
(rpc)->reply_new = (void *(*)(void))reply##_new; \
|
||||
(rpc)->reply_free = (void (*)(void *))reply##_free; \
|
||||
(rpc)->reply_complete = (int (*)(void *))reply##_complete; \
|
||||
(rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal; \
|
||||
} while (0)
|
||||
|
||||
struct evrpc_base;
|
||||
struct evhttp;
|
||||
|
||||
/* functions to start up the rpc system */
|
||||
|
||||
/** Creates a new rpc base from which RPC requests can be received
|
||||
*
|
||||
* @param server a pointer to an existing HTTP server
|
||||
* @return a newly allocated evrpc_base struct
|
||||
* @see evrpc_free()
|
||||
*/
|
||||
struct evrpc_base *evrpc_init(struct evhttp *server);
|
||||
|
||||
/**
|
||||
* Frees the evrpc base
|
||||
*
|
||||
* For now, you are responsible for making sure that no rpcs are ongoing.
|
||||
*
|
||||
* @param base the evrpc_base object to be freed
|
||||
* @see evrpc_init
|
||||
*/
|
||||
void evrpc_free(struct evrpc_base *base);
|
||||
|
||||
/** register RPCs with the HTTP Server
|
||||
*
|
||||
* registers a new RPC with the HTTP server, each RPC needs to have
|
||||
* a unique name under which it can be identified.
|
||||
*
|
||||
* @param base the evrpc_base structure in which the RPC should be
|
||||
* registered.
|
||||
* @param name the name of the RPC
|
||||
* @param request the name of the RPC request structure
|
||||
* @param reply the name of the RPC reply structure
|
||||
* @param callback the callback that should be invoked when the RPC
|
||||
* is received. The callback has the following prototype
|
||||
* void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
|
||||
* @param cbarg an additional parameter that can be passed to the callback.
|
||||
* The parameter can be used to carry around state.
|
||||
*/
|
||||
#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
|
||||
do { \
|
||||
struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \
|
||||
EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \
|
||||
evrpc_register_rpc(base, rpc, \
|
||||
(void (*)(struct evrpc_req_generic*, void *))callback, cbarg); \
|
||||
} while (0)
|
||||
|
||||
int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
|
||||
void (*)(struct evrpc_req_generic*, void *), void *);
|
||||
|
||||
/**
|
||||
* Unregisters an already registered RPC
|
||||
*
|
||||
* @param base the evrpc_base object from which to unregister an RPC
|
||||
* @param name the name of the rpc to unregister
|
||||
* @return -1 on error or 0 when successful.
|
||||
* @see EVRPC_REGISTER()
|
||||
*/
|
||||
#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name)
|
||||
|
||||
int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
|
||||
|
||||
/*
|
||||
* Client-side RPC support
|
||||
*/
|
||||
|
||||
struct evrpc_pool;
|
||||
struct evhttp_connection;
|
||||
|
||||
/**
|
||||
* provides information about the completed RPC request.
|
||||
*/
|
||||
struct evrpc_status {
|
||||
#define EVRPC_STATUS_ERR_NONE 0
|
||||
#define EVRPC_STATUS_ERR_TIMEOUT 1
|
||||
#define EVRPC_STATUS_ERR_BADPAYLOAD 2
|
||||
#define EVRPC_STATUS_ERR_UNSTARTED 3
|
||||
#define EVRPC_STATUS_ERR_HOOKABORTED 4
|
||||
int error;
|
||||
|
||||
/* for looking at headers or other information */
|
||||
struct evhttp_request *http_req;
|
||||
};
|
||||
|
||||
struct evrpc_request_wrapper {
|
||||
TAILQ_ENTRY(evrpc_request_wrapper) next;
|
||||
|
||||
/* pool on which this rpc request is being made */
|
||||
struct evrpc_pool *pool;
|
||||
|
||||
/* connection on which the request is being sent */
|
||||
struct evhttp_connection *evcon;
|
||||
|
||||
/* event for implementing request timeouts */
|
||||
struct event ev_timeout;
|
||||
|
||||
/* the name of the rpc */
|
||||
char *name;
|
||||
|
||||
/* callback */
|
||||
void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
|
||||
void *cb_arg;
|
||||
|
||||
void *request;
|
||||
void *reply;
|
||||
|
||||
/* unmarshals the buffer into the proper request structure */
|
||||
void (*request_marshal)(struct evbuffer *, void *);
|
||||
|
||||
/* removes all stored state in the reply */
|
||||
void (*reply_clear)(void *);
|
||||
|
||||
/* marshals the reply into a buffer */
|
||||
int (*reply_unmarshal)(void *, struct evbuffer*);
|
||||
};
|
||||
|
||||
/** launches an RPC and sends it to the server
|
||||
*
|
||||
* EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
|
||||
*
|
||||
* @param name the name of the RPC
|
||||
* @param pool the evrpc_pool that contains the connection objects over which
|
||||
* the request should be sent.
|
||||
* @param request a pointer to the RPC request structure - it contains the
|
||||
* data to be sent to the server.
|
||||
* @param reply a pointer to the RPC reply structure. It is going to be filled
|
||||
* if the request was answered successfully
|
||||
* @param cb the callback to invoke when the RPC request has been answered
|
||||
* @param cbarg an additional argument to be passed to the client
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \
|
||||
evrpc_send_request_##name(pool, request, reply, cb, cbarg)
|
||||
|
||||
int evrpc_make_request(struct evrpc_request_wrapper *);
|
||||
|
||||
/** creates an rpc connection pool
|
||||
*
|
||||
* a pool has a number of connections associated with it.
|
||||
* rpc requests are always made via a pool.
|
||||
*
|
||||
* @param base a pointer to an struct event_based object; can be left NULL
|
||||
* in singled-threaded applications
|
||||
* @return a newly allocated struct evrpc_pool object
|
||||
* @see evrpc_pool_free()
|
||||
*/
|
||||
struct evrpc_pool *evrpc_pool_new(struct event_base *base);
|
||||
/** frees an rpc connection pool
|
||||
*
|
||||
* @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
|
||||
* @see evrpc_pool_new()
|
||||
*/
|
||||
void evrpc_pool_free(struct evrpc_pool *pool);
|
||||
/*
|
||||
* adds a connection over which rpc can be dispatched. the connection
|
||||
* object must have been newly created.
|
||||
*/
|
||||
void evrpc_pool_add_connection(struct evrpc_pool *,
|
||||
struct evhttp_connection *);
|
||||
|
||||
/**
|
||||
* Sets the timeout in secs after which a request has to complete. The
|
||||
* RPC is completely aborted if it does not complete by then. Setting
|
||||
* the timeout to 0 means that it never timeouts and can be used to
|
||||
* implement callback type RPCs.
|
||||
*
|
||||
* Any connection already in the pool will be updated with the new
|
||||
* timeout. Connections added to the pool after set_timeout has be
|
||||
* called receive the pool timeout only if no timeout has been set
|
||||
* for the connection itself.
|
||||
*
|
||||
* @param pool a pointer to a struct evrpc_pool object
|
||||
* @param timeout_in_secs the number of seconds after which a request should
|
||||
* timeout and a failure be returned to the callback.
|
||||
*/
|
||||
void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
|
||||
|
||||
/**
|
||||
* Hooks for changing the input and output of RPCs; this can be used to
|
||||
* implement compression, authentication, encryption, ...
|
||||
*/
|
||||
|
||||
enum EVRPC_HOOK_TYPE {
|
||||
INPUT, /**< apply the function to an input hook */
|
||||
OUTPUT /**< apply the function to an output hook */
|
||||
};
|
||||
|
||||
/** adds a processing hook to either an rpc base or rpc pool
|
||||
*
|
||||
* If a hook returns -1, the processing is aborted.
|
||||
*
|
||||
* The add functions return handles that can be used for removing hooks.
|
||||
*
|
||||
* @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
|
||||
* @param hook_type either INPUT or OUTPUT
|
||||
* @param cb the callback to call when the hook is activated
|
||||
* @param cb_arg an additional argument for the callback
|
||||
* @return a handle to the hook so it can be removed later
|
||||
* @see evrpc_remove_hook()
|
||||
*/
|
||||
void *evrpc_add_hook(void *vbase,
|
||||
enum EVRPC_HOOK_TYPE hook_type,
|
||||
int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
|
||||
void *cb_arg);
|
||||
|
||||
/** removes a previously added hook
|
||||
*
|
||||
* @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
|
||||
* @param hook_type either INPUT or OUTPUT
|
||||
* @param handle a handle returned by evrpc_add_hook()
|
||||
* @return 1 on success or 0 on failure
|
||||
* @see evrpc_add_hook()
|
||||
*/
|
||||
int evrpc_remove_hook(void *vbase,
|
||||
enum EVRPC_HOOK_TYPE hook_type,
|
||||
void *handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVRPC_H_ */
|
||||
52
extra/libevent/evsignal.h
Normal file
52
extra/libevent/evsignal.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _EVSIGNAL_H_
|
||||
#define _EVSIGNAL_H_
|
||||
|
||||
typedef void (*ev_sighandler_t)(int);
|
||||
|
||||
struct evsignal_info {
|
||||
struct event_list signalqueue;
|
||||
struct event ev_signal;
|
||||
int ev_signal_pair[2];
|
||||
int ev_signal_added;
|
||||
volatile sig_atomic_t evsignal_caught;
|
||||
sig_atomic_t evsigcaught[NSIG];
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction **sh_old;
|
||||
#else
|
||||
ev_sighandler_t **sh_old;
|
||||
#endif
|
||||
int sh_old_max;
|
||||
};
|
||||
void evsignal_init(struct event_base *);
|
||||
void evsignal_process(struct event_base *);
|
||||
int evsignal_add(struct event *);
|
||||
int evsignal_del(struct event *);
|
||||
void evsignal_dealloc(struct event_base *);
|
||||
|
||||
#endif /* _EVSIGNAL_H_ */
|
||||
198
extra/libevent/evutil.c
Normal file
198
extra/libevent/evutil.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "evutil.h"
|
||||
#include "log.h"
|
||||
|
||||
int
|
||||
evutil_socketpair(int family, int type, int protocol, int fd[2])
|
||||
{
|
||||
#ifndef WIN32
|
||||
return socketpair(family, type, protocol, fd);
|
||||
#else
|
||||
/* This code is originally from Tor. Used with permission. */
|
||||
|
||||
/* This socketpair does not work when localhost is down. So
|
||||
* it's really not the same thing at all. But it's close enough
|
||||
* for now, and really, when localhost is down sometimes, we
|
||||
* have other problems too.
|
||||
*/
|
||||
int listener = -1;
|
||||
int connector = -1;
|
||||
int acceptor = -1;
|
||||
struct sockaddr_in listen_addr;
|
||||
struct sockaddr_in connect_addr;
|
||||
int size;
|
||||
int saved_errno = -1;
|
||||
|
||||
if (protocol
|
||||
#ifdef AF_UNIX
|
||||
|| family != AF_UNIX
|
||||
#endif
|
||||
) {
|
||||
EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT);
|
||||
return -1;
|
||||
}
|
||||
if (!fd) {
|
||||
EVUTIL_SET_SOCKET_ERROR(WSAEINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listener = (int)socket(AF_INET, type, 0);
|
||||
if (listener < 0)
|
||||
return -1;
|
||||
memset(&listen_addr, 0, sizeof(listen_addr));
|
||||
listen_addr.sin_family = AF_INET;
|
||||
listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
listen_addr.sin_port = 0; /* kernel chooses port. */
|
||||
if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
|
||||
== -1)
|
||||
goto tidy_up_and_fail;
|
||||
if (listen(listener, 1) == -1)
|
||||
goto tidy_up_and_fail;
|
||||
|
||||
connector = (int)socket(AF_INET, type, 0);
|
||||
if (connector < 0)
|
||||
goto tidy_up_and_fail;
|
||||
/* We want to find out the port number to connect to. */
|
||||
size = sizeof(connect_addr);
|
||||
if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
|
||||
goto tidy_up_and_fail;
|
||||
if (size != sizeof (connect_addr))
|
||||
goto abort_tidy_up_and_fail;
|
||||
if (connect(connector, (struct sockaddr *) &connect_addr,
|
||||
sizeof(connect_addr)) == -1)
|
||||
goto tidy_up_and_fail;
|
||||
|
||||
size = sizeof(listen_addr);
|
||||
acceptor = (int)accept(listener, (struct sockaddr *) &listen_addr, &size);
|
||||
if (acceptor < 0)
|
||||
goto tidy_up_and_fail;
|
||||
if (size != sizeof(listen_addr))
|
||||
goto abort_tidy_up_and_fail;
|
||||
EVUTIL_CLOSESOCKET(listener);
|
||||
/* Now check we are talking to ourself by matching port and host on the
|
||||
two sockets. */
|
||||
if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
|
||||
goto tidy_up_and_fail;
|
||||
if (size != sizeof (connect_addr)
|
||||
|| listen_addr.sin_family != connect_addr.sin_family
|
||||
|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
|
||||
|| listen_addr.sin_port != connect_addr.sin_port)
|
||||
goto abort_tidy_up_and_fail;
|
||||
fd[0] = connector;
|
||||
fd[1] = acceptor;
|
||||
|
||||
return 0;
|
||||
|
||||
abort_tidy_up_and_fail:
|
||||
saved_errno = WSAECONNABORTED;
|
||||
tidy_up_and_fail:
|
||||
if (saved_errno < 0)
|
||||
saved_errno = WSAGetLastError();
|
||||
if (listener != -1)
|
||||
EVUTIL_CLOSESOCKET(listener);
|
||||
if (connector != -1)
|
||||
EVUTIL_CLOSESOCKET(connector);
|
||||
if (acceptor != -1)
|
||||
EVUTIL_CLOSESOCKET(acceptor);
|
||||
|
||||
EVUTIL_SET_SOCKET_ERROR(saved_errno);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
evutil_make_socket_nonblocking(int fd)
|
||||
{
|
||||
#ifdef WIN32
|
||||
{
|
||||
unsigned long nonblocking = 1;
|
||||
ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
|
||||
}
|
||||
#else
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
event_warn("fcntl(O_NONBLOCK)");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
ev_int64_t
|
||||
evutil_strtoll(const char *s, char **endptr, int base)
|
||||
{
|
||||
#ifdef HAVE_STRTOLL
|
||||
return (ev_int64_t)strtoll(s, endptr, base);
|
||||
#elif SIZEOF_LONG == 8
|
||||
return (ev_int64_t)strtol(s, endptr, base);
|
||||
#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
|
||||
/* XXXX on old versions of MS APIs, we only support base
|
||||
* 10. */
|
||||
ev_int64_t r;
|
||||
if (base != 10)
|
||||
return 0;
|
||||
r = (ev_int64_t) _atoi64(s);
|
||||
while (isspace(*s))
|
||||
++s;
|
||||
while (isdigit(*s))
|
||||
++s;
|
||||
if (endptr)
|
||||
*endptr = (char*) s;
|
||||
return r;
|
||||
#elif defined(WIN32)
|
||||
return (ev_int64_t) _strtoi64(s, endptr, base);
|
||||
#else
|
||||
#error "I don't know how to parse 64-bit integers."
|
||||
#endif
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user