1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00
checkpoint.
does not compile.
This commit is contained in:
Sergei Golubchik
2010-11-25 18:17:28 +01:00
2732 changed files with 867504 additions and 20901 deletions

2384
.bzrignore

File diff suppressed because it is too large Load Diff

View File

@ -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="\

View File

@ -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

View File

@ -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
View 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"

View 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
View 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

View File

@ -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
View 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
View 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"

View File

@ -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
View 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"

View 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"

View 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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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 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
# )
make -k clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`
. "$path/autorun.sh"
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"
. "$path/SETUP.sh"
extra_flags="$amd64_cflags -D__sun -m64 -mtune=athlon64"
extra_configs="$amd64_configs $max_configs --with-libevent"
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)
LDFLAGS="-lmtmalloc -R/usr/sfw/lib/64"
export LDFLAGS
$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"

13
BUILD/compile-solaris-amd64-debug Normal file → Executable file
View File

@ -1,10 +1,11 @@
#! /bin/sh
#!/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"

View 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"

View File

@ -1,53 +1,29 @@
#! /bin/sh
#!/bin/sh
# 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
gmake -k clean || true
/bin/rm -f */.deps/*.P config.cache
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"

View File

@ -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

View File

@ -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

View File

@ -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
View 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"

View 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"

View 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"

View 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
View 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
}

View File

@ -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."

View File

@ -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.

View File

@ -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

View File

@ -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',
@ -1097,4 +1097,4 @@
) comment='Stored Procedures';
--

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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!

View File

@ -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,7 +64,12 @@ dist-hook:
test ! -f $(top_srcdir)/configure.am || \
$(INSTALL_DATA) $(top_srcdir)/configure.am $(distdir)
all-local: @ABI_CHECK@
# 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:
support-files/build-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,51 +90,57 @@ 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" ; \
fi
fi
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

322
README
View File

@ -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,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.
*
*
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.
*
****************************************************************************
Copyright (c) 1998 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. *
*
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. *
***************************************************************************
------------------------------------------------------
@ -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.
@ -588,7 +523,7 @@ Fred Fish's Dbug Library
Use of any of this software is governed by the terms of the license below:
*
*
* N O T I C E *
* *
* Copyright Abandoned, 1987, Fred Fish *
@ -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<EFBFBD>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<EFBFBD>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<EFBFBD>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.
*/
***************************************************************************

View File

@ -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)

View File

@ -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:

View File

@ -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 */
};
/**

View File

@ -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 */

View File

@ -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[] = {
"&", "&amp;",
"<", "&lt;",
@ -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,12 +2021,12 @@ static COMMANDS *find_command(char *name,char cmd_char)
for (uint i= 0; commands[i].name; i++)
{
if (commands[i].func &&
((name &&
!my_strnncoll(&my_charset_latin1, (uchar*)name, len,
(uchar*)commands[i].name,len) &&
!commands[i].name[len] &&
(!end || (end && commands[i].takes_params))) ||
(!name && commands[i].cmd_char == cmd_char)))
(((name &&
!my_strnncoll(&my_charset_latin1, (uchar*) name, len,
(uchar*) commands[i].name, len) &&
!commands[i].name[len] &&
(!end || (end && commands[i].takes_params)))) ||
(!name && commands[i].cmd_char == cmd_char)))
{
DBUG_PRINT("exit",("found command: %s", commands[i].name));
DBUG_RETURN(&commands[i]);
@ -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 == '#' ||
(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.
*/
(my_isspace(charset_info,pos[2]) ||
!pos[2])))))
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.
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]) ||
(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)
@ -4294,7 +4387,13 @@ 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;
}
@ -4730,7 +4837,7 @@ static void mysql_end_timer(ulong start_time,char *buff)
strmov(strend(buff),")");
}
static const char* construct_prompt()
static const char *construct_prompt()
{
processed_prompt.free(); // Erase the old prompt
time_t lclock = time(NULL); // Get the date struct
@ -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;

View File

@ -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.",
&not_used, &not_used, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"datadir", 'd',
"Not used by mysql_upgrade. Only for backward compatibility.",
@ -79,18 +83,17 @@ 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},
{"host",'h', "Connect to host.", 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',
"Password to use when connecting to server. If password is not given,"
@ -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,7 +446,8 @@ static void find_tool(char *tool_executable_name, const char *tool_name,
len, self_name, FN_LIBCHAR, tool_name);
}
verbose("Looking for '%s' as: %s", tool_name, tool_executable_name);
if (opt_verbose)
verbose("Looking for '%s' as: %s", tool_name, tool_executable_name);
/*
Make sure it can be executed
@ -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);

View File

@ -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);
@ -1078,16 +1165,23 @@ static void usage(void)
my_print_variables(my_long_options);
print_defaults("my",load_default_groups);
puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
create databasename Create a new database\n\
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-hosts Flush all cached hosts\n\
flush-logs Flush all logs\n\
flush-status Clear status variables\n\
flush-tables Flush all tables\n\
flush-threads Flush the thread cache\n\
flush-privileges Reload grant tables (same as reload)\n\
create databasename Create a new database\n\
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-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");

View File

@ -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,
set the temp_buf to NULL so that memory isn't freed twice.
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"

View File

@ -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,7 +772,15 @@ static void print_result()
printf("%-50s %s", row[0], row[3]);
else if (!status && changed)
{
printf("%s\n%-9s: %s", row[0], row[2], row[3]);
/*
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;
}

View File

@ -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);
}

View File

@ -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},

View File

@ -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,

View File

@ -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,10 +479,10 @@ 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",
sysret);
if (pre_system && (sysret= system(pre_system)) != 0)
fprintf(stderr,
"Warning: Execution of pre_system option returned %d.\n",
sysret);
/*
Pre statements are always run after all other logic so they can
@ -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",
sysret);
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,14 +601,17 @@ 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.",
&default_engine, &default_engine, 0,
{"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,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@ -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);
@ -973,8 +991,8 @@ build_update_string(void)
static statement *
build_insert_string(void)
{
char buf[HUGE_STRING_LENGTH];
unsigned int col_count;
char buf[HUGE_STRING_LENGTH];
unsigned int col_count;
statement *ptr;
DYNAMIC_STRING insert_string;
DBUG_ENTER("build_insert_string");
@ -1064,8 +1082,8 @@ build_insert_string(void)
static statement *
build_select_string(my_bool key)
{
char buf[HUGE_STRING_LENGTH];
unsigned int col_count;
char buf[HUGE_STRING_LENGTH];
unsigned int col_count;
statement *ptr;
static DYNAMIC_STRING query_string;
DBUG_ENTER("build_select_string");
@ -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,10 +1907,17 @@ limit_not_met:
{
if (mysql_field_count(mysql))
{
result= mysql_store_result(mysql);
while ((row = mysql_fetch_row(result)))
counter++;
mysql_free_result(result);
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++;
@ -1933,17 +1963,27 @@ parse_option(const char *origin, option_string **stmt, char delm)
uint count= 0; /* We know that there is always one */
for (tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
(retstr= strchr(ptr, delm));
tmp->next= (option_string *)my_malloc(sizeof(option_string),
MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
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,13 +2004,15 @@ 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++;
}
if (ptr != origin+length)
if (ptr != origin + length)
{
char *origin_ptr;
@ -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;
@ -2029,7 +2071,7 @@ parse_delimiter(const char *script, statement **stmt, char delm)
if (ptr != script+length)
{
tmp->string= my_strndup(ptr, (uint)((script + length) - ptr),
MYF(MY_FAE));
MYF(MY_FAE));
tmp->length= (size_t)((script + length) - ptr);
count++;
}
@ -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,

View File

@ -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;
}
@ -3372,7 +3418,7 @@ void do_rmdir(struct st_command *command)
int error;
static DYNAMIC_STRING ds_dirname;
const struct command_arg rmdir_args[] = {
{"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"}
{ "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove" }
};
DBUG_ENTER("do_rmdir");
@ -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,9 +3816,10 @@ 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
so the failure can be analyzed, but only if it was not
expected to fail.
/*
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.
*/
show_diff(&ds_res, ds_filename.str, ds_filename2.str);
log_file.write(&ds_res);
@ -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,13 +3925,15 @@ void do_change_user(struct st_command *command)
}
if (!ds_user.length)
{
dynstr_set(&ds_user, mysql->user);
if (!ds_passwd.length)
dynstr_set(&ds_passwd, mysql->passwd);
if (!ds_passwd.length)
dynstr_set(&ds_passwd, mysql->passwd);
if (!ds_db.length)
dynstr_set(&ds_db, mysql->db);
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,7 +5364,8 @@ void do_connect(struct st_command *command)
con_options= ds_options.str;
while (*con_options)
{
char* end;
size_t length;
char *end;
/* Step past any spaces in beginning of option*/
while (*con_options && my_isspace(charset_info, *con_options))
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)
@ -5402,14 +5457,13 @@ void do_connect(struct st_command *command)
mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str);
mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
}
else if(shared_memory_base_name)
else if (shared_memory_base_name)
{
mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
shared_memory_base_name);
}
#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,8 +7411,17 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command,
mysql_free_result(res); /* Free normal result set with meta data */
/* Clear prepare warnings */
dynstr_set(&ds_prepare_warnings, NULL);
/*
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));

View File

@ -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

View File

@ -699,7 +699,7 @@ rl_function_of_keyseq (keyseq, map, type)
{
unsigned char ic = keyseq[i];
if (META_CHAR_FOR_UCHAR (ic) && _rl_convert_meta_chars_to_ascii)
if (META_CHAR_FOR_UCHAR(ic) && _rl_convert_meta_chars_to_ascii)
{
if (map[ESC].type == ISKMAP)
{

View File

@ -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)

View File

@ -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

View File

@ -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;
@ -1893,7 +1889,7 @@ rl_character_len (c, pos)
uc = (unsigned char)c;
if (META_CHAR_FOR_UCHAR (uc))
if (META_CHAR_FOR_UCHAR(uc))
return ((_rl_output_meta_chars == 0) ? 4 : 1);
if (uc == '\t')

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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);

View 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" ])
])

View 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__])]
)]
)

View File

@ -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])
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, [^.+[/$]], [\&])"
__MYSQL_EMIT_CHECK_RESULT($3,[yes])
m4_ifdef([$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

View File

@ -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(
@ -1842,7 +1855,7 @@ AC_CACHE_CHECK([whether the compiler provides atomic builtins],
)])
if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
[Define to 1 if compiler provides atomic builtins.])
[Define to 1 if compiler provides atomic builtins.])
fi
AC_CACHE_CHECK([whether the OS provides atomic_* functions like Solaris],
@ -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 ""

View File

@ -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

View File

@ -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':
@ -558,7 +566,7 @@ int DbugParse(CODE_STATE *cs, const char *control)
{
if (DEBUGGING)
stack->keywords= ListDel(stack->keywords, control, end);
break;
break;
}
stack->keywords= ListAdd(stack->keywords, control, end);
stack->flags |= DEBUG_ON;
@ -700,9 +708,14 @@ 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;
}
#define framep_trace_flag(cs, frp) (frp ? \
frp->level & TRACE_ON : \
(ListFlags(cs->stack->functions) & INCLUDE) ? \
@ -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 (!cs->locked)
pthread_mutex_lock(&THR_LOCK_dbug);
if (_db_keyword_(cs, keyword, 0))
{
if (!cs->locked)
pthread_mutex_lock(&THR_LOCK_dbug);
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 &&
cs->level <= cs->stack->maxdepth &&
InList(cs->stack->p_functions, cs->func) & (INCLUDE|MATCHED) &&
InList(cs->stack->processes, cs->process) & (INCLUDE|MATCHED);
return (PROFILING &&
cs->level <= cs->stack->maxdepth &&
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,7 +2102,8 @@ static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
{
if (fp && fp != stderr && fp != stdout && fclose(fp) == EOF)
{
pthread_mutex_lock(&THR_LOCK_dbug);
if (!cs->locked)
pthread_mutex_lock(&THR_LOCK_dbug);
(void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
perror("");
DbugFlush(cs);

View File

@ -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;
}

View File

@ -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")

View File

@ -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

View File

@ -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},

View 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)

View 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
View 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.

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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
View 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;
}

View 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_ */

View File

@ -0,0 +1,488 @@
/* $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#ifndef WIN32
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
#endif
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_REVERSE(var, head, 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_ */

View File

@ -0,0 +1,677 @@
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root))) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-back tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
void name##_RB_INSERT_COLOR(struct name *, struct type *); \
void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
struct type *name##_RB_REMOVE(struct name *, struct type *); \
struct type *name##_RB_INSERT(struct name *, struct type *); \
struct type *name##_RB_FIND(struct name *, struct type *); \
struct type *name##_RB_NEXT(struct type *); \
struct type *name##_RB_MINMAX(struct name *, int); \
\
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)))\
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)))\
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field))) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field))); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#endif /* _SYS_TREE_H_ */

421
extra/libevent/devpoll.c Normal file
View 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
View 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 */

View 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
View 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

File diff suppressed because it is too large Load Diff

528
extra/libevent/evdns.h Normal file
View 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 */

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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 &lt;, &gt;, &quot;,
* &#039; and &amp; 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
View 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 */

View 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
View 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
View 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
View 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_ */

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