mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-29 15:43:52 +00:00
update controller image and some dependencies
This commit is contained in:
parent
c1384422c3
commit
183a9d7088
@ -1,13 +1,23 @@
|
||||
# Dockerfile for building ZeroTier Central Controllers
|
||||
FROM centos:8 as builder
|
||||
FROM ubuntu:jammy as builder
|
||||
MAINTAINER Adam Ierymekno <adam.ierymenko@zerotier.com>, Grant Limberg <grant.limberg@zerotier.com>
|
||||
|
||||
ARG git_branch=master
|
||||
|
||||
RUN yum update -y
|
||||
RUN yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
|
||||
RUN dnf -qy module disable postgresql
|
||||
RUN yum -y install epel-release && yum -y update && yum clean all
|
||||
RUN yum groupinstall -y "Development Tools" && yum clean all
|
||||
RUN yum install -y bash cmake postgresql10 postgresql10-devel clang jemalloc jemalloc-devel libpqxx libpqxx-devel openssl-devel && yum clean all
|
||||
RUN apt update && apt upgrade -y
|
||||
RUN apt -y install \
|
||||
build-essential \
|
||||
pkg-config \
|
||||
bash \
|
||||
clang \
|
||||
libjemalloc2 \
|
||||
libjemalloc-dev \
|
||||
libpq5 \
|
||||
libpq-dev \
|
||||
openssl \
|
||||
libssl-dev \
|
||||
postgresql-client \
|
||||
postgresql-client-common \
|
||||
curl
|
||||
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
|
@ -1,5 +1,8 @@
|
||||
FROM centos:8
|
||||
RUN yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
|
||||
RUN dnf -qy module disable postgresql
|
||||
RUN yum -y install epel-release && yum -y update && yum clean all
|
||||
RUN yum install -y jemalloc jemalloc-devel postgresql10 libpqxx libpqxx-devel && yum clean all
|
||||
FROM ubuntu:jammy
|
||||
RUN apt update && apt upgrade -y
|
||||
RUN apt -y install \
|
||||
postgresql-client \
|
||||
postgresql-client-common \
|
||||
libjemalloc2 \
|
||||
libpq5 \
|
||||
curl
|
||||
|
@ -83,12 +83,12 @@ if [ -n "$DB_SERVER_CA" ]; then
|
||||
echo "secret list"
|
||||
chmod 600 /secrets/db/*.pem
|
||||
ls -l /secrets/db/
|
||||
until /usr/pgsql-10/bin/pg_isready -h ${ZT_DB_HOST} -p ${ZT_DB_PORT} -d "sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}"; do
|
||||
until /usr/bin/pg_isready -h ${ZT_DB_HOST} -p ${ZT_DB_PORT} -d "sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}"; do
|
||||
echo "Waiting for PostgreSQL...";
|
||||
sleep 2;
|
||||
done
|
||||
else
|
||||
until /usr/pgsql-10/bin/pg_isready -h ${ZT_DB_HOST} -p ${ZT_DB_PORT}; do
|
||||
until /usr/bin/pg_isready -h ${ZT_DB_HOST} -p ${ZT_DB_PORT}; do
|
||||
echo "Waiting for PostgreSQL...";
|
||||
sleep 2;
|
||||
done
|
||||
@ -96,5 +96,5 @@ fi
|
||||
|
||||
export GLIBCXX_FORCE_NEW=1
|
||||
export GLIBCPP_FORCE_NEW=1
|
||||
export LD_PRELOAD="/usr/lib64/libjemalloc.so"
|
||||
export LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
|
||||
exec /usr/local/bin/zerotier-one -p${ZT_CONTROLLER_PORT:-$DEFAULT_PORT} /var/lib/zerotier-one
|
||||
|
9
ext/hiredis-1.0.2/.gitignore
vendored
Normal file
9
ext/hiredis-1.0.2/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/hiredis-test
|
||||
/examples/hiredis-example*
|
||||
/*.o
|
||||
/*.so
|
||||
/*.dylib
|
||||
/*.a
|
||||
/*.pc
|
||||
*.dSYM
|
||||
tags
|
131
ext/hiredis-1.0.2/.travis.yml
Normal file
131
ext/hiredis-1.0.2/.travis.yml
Normal file
@ -0,0 +1,131 @@
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
dist: bionic
|
||||
|
||||
branches:
|
||||
only:
|
||||
- staging
|
||||
- trying
|
||||
- master
|
||||
- /^release\/.*$/
|
||||
|
||||
install:
|
||||
- if [ "$BITS" == "64" ]; then
|
||||
wget https://github.com/redis/redis/archive/6.0.6.tar.gz;
|
||||
tar -xzvf 6.0.6.tar.gz;
|
||||
pushd redis-6.0.6 && BUILD_TLS=yes make && export PATH=$PWD/src:$PATH && popd;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.6.2-10.13-HighSierra.pkg;
|
||||
sudo installer -pkg MacPorts-2.6.2-10.13-HighSierra.pkg -target /;
|
||||
export PATH=$PATH:/opt/local/bin && sudo port -v selfupdate;
|
||||
sudo port -N install openssl redis;
|
||||
fi;
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:chris-lea/redis-server'
|
||||
packages:
|
||||
- libc6-dbg
|
||||
- libc6-dev
|
||||
- libc6:i386
|
||||
- libc6-dev-i386
|
||||
- libc6-dbg:i386
|
||||
- gcc-multilib
|
||||
- g++-multilib
|
||||
- libssl-dev
|
||||
- libssl-dev:i386
|
||||
- valgrind
|
||||
- redis
|
||||
|
||||
env:
|
||||
- BITS="32"
|
||||
- BITS="64"
|
||||
|
||||
script:
|
||||
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON";
|
||||
if [ "$BITS" == "64" ]; then
|
||||
EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DENABLE_SSL_TESTS:BOOL=ON";
|
||||
fi;
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
if [ "$BITS" == "32" ]; then
|
||||
CFLAGS="-m32 -Werror";
|
||||
CXXFLAGS="-m32 -Werror";
|
||||
LDFLAGS="-m32";
|
||||
EXTRA_CMAKE_OPTS=;
|
||||
else
|
||||
CFLAGS="-Werror";
|
||||
CXXFLAGS="-Werror";
|
||||
fi;
|
||||
else
|
||||
TEST_PREFIX="valgrind --track-origins=yes --leak-check=full";
|
||||
if [ "$BITS" == "32" ]; then
|
||||
CFLAGS="-m32 -Werror";
|
||||
CXXFLAGS="-m32 -Werror";
|
||||
LDFLAGS="-m32";
|
||||
EXTRA_CMAKE_OPTS=;
|
||||
else
|
||||
CFLAGS="-Werror";
|
||||
CXXFLAGS="-Werror";
|
||||
fi;
|
||||
fi;
|
||||
export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS
|
||||
- make && make clean;
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
if [ "$BITS" == "64" ]; then
|
||||
OPENSSL_PREFIX="$(ls -d /usr/local/Cellar/openssl@1.1/*)" USE_SSL=1 make;
|
||||
fi;
|
||||
else
|
||||
USE_SSL=1 make;
|
||||
fi;
|
||||
- mkdir build/ && cd build/
|
||||
- cmake .. ${EXTRA_CMAKE_OPTS}
|
||||
- make VERBOSE=1
|
||||
- if [ "$BITS" == "64" ]; then
|
||||
TEST_SSL=1 SKIPS_AS_FAILS=1 ctest -V;
|
||||
else
|
||||
SKIPS_AS_FAILS=1 ctest -V;
|
||||
fi;
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# Windows MinGW cross compile on Linux
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: mingw
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- ninja-build
|
||||
- gcc-mingw-w64-x86-64
|
||||
- g++-mingw-w64-x86-64
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on
|
||||
- ninja -v
|
||||
|
||||
# Windows MSVC 2017
|
||||
- os: windows
|
||||
compiler: msvc
|
||||
env:
|
||||
- MATRIX_EVAL="CC=cl.exe && CXX=cl.exe"
|
||||
before_install:
|
||||
- eval "${MATRIX_EVAL}"
|
||||
install:
|
||||
- choco install ninja
|
||||
- choco install -y memurai-developer
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
- cmd.exe //C 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat' amd64 '&&'
|
||||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DENABLE_EXAMPLES=ON '&&' ninja -v
|
||||
- ./hiredis-test.exe
|
364
ext/hiredis-1.0.2/CHANGELOG.md
Normal file
364
ext/hiredis-1.0.2/CHANGELOG.md
Normal file
@ -0,0 +1,364 @@
|
||||
## [1.0.2](https://github.com/redis/hiredis/tree/v1.0.2) - (2021-10-07)
|
||||
|
||||
Announcing Hiredis v1.0.2, which fixes CVE-2021-32765 but returns the SONAME to the correct value of `1.0.0`.
|
||||
|
||||
- [Revert SONAME bump](https://github.com/redis/hiredis/commit/d4e6f109a064690cde64765c654e679fea1d3548)
|
||||
([Michael Grunder](https://github.com/michael-grunder))
|
||||
|
||||
## [1.0.1](https://github.com/redis/hiredis/tree/v1.0.1) - (2021-10-04)
|
||||
|
||||
<span style="color:red">This release erroneously bumped the SONAME, please use [1.0.2](https://github.com/redis/hiredis/tree/v1.0.2)</span>
|
||||
|
||||
Announcing Hiredis v1.0.1, a security release fixing CVE-2021-32765
|
||||
|
||||
- Fix for [CVE-2021-32765](https://github.com/redis/hiredis/security/advisories/GHSA-hfm9-39pp-55p2)
|
||||
[commit](https://github.com/redis/hiredis/commit/76a7b10005c70babee357a7d0f2becf28ec7ed1e)
|
||||
([Yossi Gottlieb](https://github.com/yossigo))
|
||||
|
||||
_Thanks to [Yossi Gottlieb](https://github.com/yossigo) for the security fix and to [Microsoft Security Vulnerability Research](https://www.microsoft.com/en-us/msrc/msvr) for finding the bug._ :sparkling_heart:
|
||||
|
||||
## [1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) - (2020-08-03)
|
||||
|
||||
Announcing Hiredis v1.0.0, which adds support for RESP3, SSL connections, allocator injection, and better Windows support! :tada:
|
||||
|
||||
_A big thanks to everyone who helped with this release. The following list includes everyone who contributed at least five lines, sorted by lines contributed._ :sparkling_heart:
|
||||
|
||||
[Michael Grunder](https://github.com/michael-grunder), [Yossi Gottlieb](https://github.com/yossigo),
|
||||
[Mark Nunberg](https://github.com/mnunberg), [Marcus Geelnard](https://github.com/mbitsnbites),
|
||||
[Justin Brewer](https://github.com/justinbrewer), [Valentino Geron](https://github.com/valentinogeron),
|
||||
[Minun Dragonation](https://github.com/dragonation), [Omri Steiner](https://github.com/OmriSteiner),
|
||||
[Sangmoon Yi](https://github.com/jman-krafton), [Jinjiazh](https://github.com/jinjiazhang),
|
||||
[Odin Hultgren Van Der Horst](https://github.com/Miniwoffer), [Muhammad Zahalqa](https://github.com/tryfinally),
|
||||
[Nick Rivera](https://github.com/heronr), [Qi Yang](https://github.com/movebean),
|
||||
[kevin1018](https://github.com/kevin1018)
|
||||
|
||||
[Full Changelog](https://github.com/redis/hiredis/compare/v0.14.1...v1.0.0)
|
||||
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* `redisOptions` now has two timeout fields. One for connecting, and one for commands. If you're presently using `options->timeout` you will need to change it to use `options->connect_timeout`. (See [example](https://github.com/redis/hiredis/commit/38b5ae543f5c99eb4ccabbe277770fc6bc81226f#diff-86ba39d37aa829c8c82624cce4f049fbL36))
|
||||
|
||||
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now protocol errors. This is consistent
|
||||
with the RESP specification. On 32-bit platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.
|
||||
|
||||
**New features:**
|
||||
- Support for RESP3
|
||||
[\#697](https://github.com/redis/hiredis/pull/697),
|
||||
[\#805](https://github.com/redis/hiredis/pull/805),
|
||||
[\#819](https://github.com/redis/hiredis/pull/819),
|
||||
[\#841](https://github.com/redis/hiredis/pull/841)
|
||||
([Yossi Gottlieb](https://github.com/yossigo), [Michael Grunder](https://github.com/michael-grunder))
|
||||
- Support for SSL connections
|
||||
[\#645](https://github.com/redis/hiredis/pull/645),
|
||||
[\#699](https://github.com/redis/hiredis/pull/699),
|
||||
[\#702](https://github.com/redis/hiredis/pull/702),
|
||||
[\#708](https://github.com/redis/hiredis/pull/708),
|
||||
[\#711](https://github.com/redis/hiredis/pull/711),
|
||||
[\#821](https://github.com/redis/hiredis/pull/821),
|
||||
[more](https://github.com/redis/hiredis/pulls?q=is%3Apr+is%3Amerged+SSL)
|
||||
([Mark Nunberg](https://github.com/mnunberg), [Yossi Gottlieb](https://github.com/yossigo))
|
||||
- Run-time allocator injection
|
||||
[\#800](https://github.com/redis/hiredis/pull/800)
|
||||
([Michael Grunder](https://github.com/michael-grunder))
|
||||
- Improved Windows support (including MinGW and Windows CI)
|
||||
[\#652](https://github.com/redis/hiredis/pull/652),
|
||||
[\#663](https://github.com/redis/hiredis/pull/663)
|
||||
([Marcus Geelnard](https://www.bitsnbites.eu/author/m/))
|
||||
- Adds support for distinct connect and command timeouts
|
||||
[\#839](https://github.com/redis/hiredis/pull/839),
|
||||
[\#829](https://github.com/redis/hiredis/pull/829)
|
||||
([Valentino Geron](https://github.com/valentinogeron))
|
||||
- Add generic pointer and destructor to `redisContext` that users can use for context.
|
||||
[\#855](https://github.com/redis/hiredis/pull/855)
|
||||
([Michael Grunder](https://github.com/michael-grunder))
|
||||
|
||||
**Closed issues (that involved code changes):**
|
||||
|
||||
- Makefile does not install TLS libraries [\#809](https://github.com/redis/hiredis/issues/809)
|
||||
- redisConnectWithOptions should not set command timeout [\#722](https://github.com/redis/hiredis/issues/722), [\#829](https://github.com/redis/hiredis/pull/829) ([valentinogeron](https://github.com/valentinogeron))
|
||||
- Fix integer overflow in `sdsrange` [\#827](https://github.com/redis/hiredis/issues/827)
|
||||
- INFO & CLUSTER commands failed when using RESP3 [\#802](https://github.com/redis/hiredis/issues/802)
|
||||
- Windows compatibility patches [\#687](https://github.com/redis/hiredis/issues/687), [\#838](https://github.com/redis/hiredis/issues/838), [\#842](https://github.com/redis/hiredis/issues/842)
|
||||
- RESP3 PUSH messages incorrectly use pending callback [\#825](https://github.com/redis/hiredis/issues/825)
|
||||
- Asynchronous PSUBSCRIBE command fails when using RESP3 [\#815](https://github.com/redis/hiredis/issues/815)
|
||||
- New SSL API [\#804](https://github.com/redis/hiredis/issues/804), [\#813](https://github.com/redis/hiredis/issues/813)
|
||||
- Hard-coded limit of nested reply depth [\#794](https://github.com/redis/hiredis/issues/794)
|
||||
- Fix TCP_NODELAY in Windows/OSX [\#679](https://github.com/redis/hiredis/issues/679), [\#690](https://github.com/redis/hiredis/issues/690), [\#779](https://github.com/redis/hiredis/issues/779), [\#785](https://github.com/redis/hiredis/issues/785),
|
||||
- Added timers to libev adapter. [\#778](https://github.com/redis/hiredis/issues/778), [\#795](https://github.com/redis/hiredis/pull/795)
|
||||
- Initialization discards const qualifier [\#777](https://github.com/redis/hiredis/issues/777)
|
||||
- \[BUG\]\[MinGW64\] Error setting socket timeout [\#775](https://github.com/redis/hiredis/issues/775)
|
||||
- undefined reference to hi_malloc [\#769](https://github.com/redis/hiredis/issues/769)
|
||||
- hiredis pkg-config file incorrectly ignores multiarch libdir spec'n [\#767](https://github.com/redis/hiredis/issues/767)
|
||||
- Don't use -G to build shared object on Solaris [\#757](https://github.com/redis/hiredis/issues/757)
|
||||
- error when make USE\_SSL=1 [\#748](https://github.com/redis/hiredis/issues/748)
|
||||
- Allow to change SSL Mode [\#646](https://github.com/redis/hiredis/issues/646)
|
||||
- hiredis/adapters/libevent.h memleak [\#618](https://github.com/redis/hiredis/issues/618)
|
||||
- redisLibuvPoll crash when server closes the connetion [\#545](https://github.com/redis/hiredis/issues/545)
|
||||
- about redisAsyncDisconnect question [\#518](https://github.com/redis/hiredis/issues/518)
|
||||
- hiredis adapters libuv error for help [\#508](https://github.com/redis/hiredis/issues/508)
|
||||
- API/ABI changes analysis [\#506](https://github.com/redis/hiredis/issues/506)
|
||||
- Memory leak patch in Redis [\#502](https://github.com/redis/hiredis/issues/502)
|
||||
- Remove the depth limitation [\#421](https://github.com/redis/hiredis/issues/421)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Move SSL management to a distinct private pointer [\#855](https://github.com/redis/hiredis/pull/855) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Move include to sockcompat.h to maintain style [\#850](https://github.com/redis/hiredis/pull/850) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Remove erroneous tag and add license to push example [\#849](https://github.com/redis/hiredis/pull/849) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- fix windows compiling with mingw [\#848](https://github.com/redis/hiredis/pull/848) ([rmalizia44](https://github.com/rmalizia44))
|
||||
- Some Windows quality of life improvements. [\#846](https://github.com/redis/hiredis/pull/846) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use \_WIN32 define instead of WIN32 [\#845](https://github.com/redis/hiredis/pull/845) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Non Linux CI fixes [\#844](https://github.com/redis/hiredis/pull/844) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Resp3 oob push support [\#841](https://github.com/redis/hiredis/pull/841) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- fix \#785: defer TCP\_NODELAY in async tcp connections [\#836](https://github.com/redis/hiredis/pull/836) ([OmriSteiner](https://github.com/OmriSteiner))
|
||||
- sdsrange overflow fix [\#830](https://github.com/redis/hiredis/pull/830) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use explicit pointer casting for c++ compatibility [\#826](https://github.com/redis/hiredis/pull/826) ([aureus1](https://github.com/aureus1))
|
||||
- Document allocator injection and completeness fix in test.c [\#824](https://github.com/redis/hiredis/pull/824) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use unique names for allocator struct members [\#823](https://github.com/redis/hiredis/pull/823) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- New SSL API to replace redisSecureConnection\(\). [\#821](https://github.com/redis/hiredis/pull/821) ([yossigo](https://github.com/yossigo))
|
||||
- Add logic to handle RESP3 push messages [\#819](https://github.com/redis/hiredis/pull/819) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use standrad isxdigit instead of custom helper function. [\#814](https://github.com/redis/hiredis/pull/814) ([tryfinally](https://github.com/tryfinally))
|
||||
- Fix missing SSL build/install options. [\#812](https://github.com/redis/hiredis/pull/812) ([yossigo](https://github.com/yossigo))
|
||||
- Add link to ABI tracker [\#808](https://github.com/redis/hiredis/pull/808) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Resp3 verbatim string support [\#805](https://github.com/redis/hiredis/pull/805) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Allow users to replace allocator and handle OOM everywhere. [\#800](https://github.com/redis/hiredis/pull/800) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Remove nested depth limitation. [\#797](https://github.com/redis/hiredis/pull/797) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Attempt to fix compilation on Solaris [\#796](https://github.com/redis/hiredis/pull/796) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Support timeouts in libev adapater [\#795](https://github.com/redis/hiredis/pull/795) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Fix pkgconfig when installing to a custom lib dir [\#793](https://github.com/redis/hiredis/pull/793) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Fix USE\_SSL=1 make/cmake on OSX and CMake tests [\#789](https://github.com/redis/hiredis/pull/789) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Use correct libuv call on Windows [\#784](https://github.com/redis/hiredis/pull/784) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Added CMake package config and fixed hiredis\_ssl on Windows [\#783](https://github.com/redis/hiredis/pull/783) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- CMake: Set hiredis\_ssl shared object version. [\#780](https://github.com/redis/hiredis/pull/780) ([yossigo](https://github.com/yossigo))
|
||||
- Win32 tests and timeout fix [\#776](https://github.com/redis/hiredis/pull/776) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Provides an optional cleanup callback for async data. [\#768](https://github.com/redis/hiredis/pull/768) ([heronr](https://github.com/heronr))
|
||||
- Housekeeping fixes [\#764](https://github.com/redis/hiredis/pull/764) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- install alloc.h [\#756](https://github.com/redis/hiredis/pull/756) ([ch1aki](https://github.com/ch1aki))
|
||||
- fix spelling mistakes [\#746](https://github.com/redis/hiredis/pull/746) ([ShooterIT](https://github.com/ShooterIT))
|
||||
- Free the reply in redisGetReply when passed NULL [\#741](https://github.com/redis/hiredis/pull/741) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Fix dead code in sslLogCallback relating to should\_log variable. [\#737](https://github.com/redis/hiredis/pull/737) ([natoscott](https://github.com/natoscott))
|
||||
- Fix typo in dict.c. [\#731](https://github.com/redis/hiredis/pull/731) ([Kevin-Xi](https://github.com/Kevin-Xi))
|
||||
- Adding an option to DISABLE\_TESTS [\#727](https://github.com/redis/hiredis/pull/727) ([pbotros](https://github.com/pbotros))
|
||||
- Update README with SSL support. [\#720](https://github.com/redis/hiredis/pull/720) ([yossigo](https://github.com/yossigo))
|
||||
- Fixes leaks in unit tests [\#715](https://github.com/redis/hiredis/pull/715) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- SSL Tests [\#711](https://github.com/redis/hiredis/pull/711) ([yossigo](https://github.com/yossigo))
|
||||
- SSL Reorganization [\#708](https://github.com/redis/hiredis/pull/708) ([yossigo](https://github.com/yossigo))
|
||||
- Fix MSVC build. [\#706](https://github.com/redis/hiredis/pull/706) ([yossigo](https://github.com/yossigo))
|
||||
- SSL: Properly report SSL\_connect\(\) errors. [\#702](https://github.com/redis/hiredis/pull/702) ([yossigo](https://github.com/yossigo))
|
||||
- Silent SSL trace to stdout by default. [\#699](https://github.com/redis/hiredis/pull/699) ([yossigo](https://github.com/yossigo))
|
||||
- Port RESP3 support from Redis. [\#697](https://github.com/redis/hiredis/pull/697) ([yossigo](https://github.com/yossigo))
|
||||
- Removed whitespace before newline [\#691](https://github.com/redis/hiredis/pull/691) ([Miniwoffer](https://github.com/Miniwoffer))
|
||||
- Add install adapters header files [\#688](https://github.com/redis/hiredis/pull/688) ([kevin1018](https://github.com/kevin1018))
|
||||
- Remove unnecessary null check before free [\#684](https://github.com/redis/hiredis/pull/684) ([qlyoung](https://github.com/qlyoung))
|
||||
- redisReaderGetReply leak memory [\#671](https://github.com/redis/hiredis/pull/671) ([movebean](https://github.com/movebean))
|
||||
- fix timeout code in windows [\#670](https://github.com/redis/hiredis/pull/670) ([jman-krafton](https://github.com/jman-krafton))
|
||||
- test: fix errstr matching for musl libc [\#665](https://github.com/redis/hiredis/pull/665) ([ghost](https://github.com/ghost))
|
||||
- Windows: MinGW fixes and Windows Travis builders [\#663](https://github.com/redis/hiredis/pull/663) ([mbitsnbites](https://github.com/mbitsnbites))
|
||||
- The setsockopt and getsockopt API diffs from BSD socket and WSA one [\#662](https://github.com/redis/hiredis/pull/662) ([dragonation](https://github.com/dragonation))
|
||||
- Fix Compile Error On Windows \(Visual Studio\) [\#658](https://github.com/redis/hiredis/pull/658) ([jinjiazhang](https://github.com/jinjiazhang))
|
||||
- Fix NXDOMAIN test case [\#653](https://github.com/redis/hiredis/pull/653) ([michael-grunder](https://github.com/michael-grunder))
|
||||
- Add MinGW support [\#652](https://github.com/redis/hiredis/pull/652) ([mbitsnbites](https://github.com/mbitsnbites))
|
||||
- SSL Support [\#645](https://github.com/redis/hiredis/pull/645) ([mnunberg](https://github.com/mnunberg))
|
||||
- Fix Invalid argument after redisAsyncConnectUnix [\#644](https://github.com/redis/hiredis/pull/644) ([codehz](https://github.com/codehz))
|
||||
- Makefile: use predefined AR [\#632](https://github.com/redis/hiredis/pull/632) ([Mic92](https://github.com/Mic92))
|
||||
- FreeBSD build fix [\#628](https://github.com/redis/hiredis/pull/628) ([devnexen](https://github.com/devnexen))
|
||||
- Fix errors not propagating properly with libuv.h. [\#624](https://github.com/redis/hiredis/pull/624) ([yossigo](https://github.com/yossigo))
|
||||
- Update README.md [\#621](https://github.com/redis/hiredis/pull/621) ([Crunsher](https://github.com/Crunsher))
|
||||
- Fix redisBufferRead documentation [\#620](https://github.com/redis/hiredis/pull/620) ([hacst](https://github.com/hacst))
|
||||
- Add CPPFLAGS to REAL\_CFLAGS [\#614](https://github.com/redis/hiredis/pull/614) ([thomaslee](https://github.com/thomaslee))
|
||||
- Update createArray to take size\_t [\#597](https://github.com/redis/hiredis/pull/597) ([justinbrewer](https://github.com/justinbrewer))
|
||||
- fix common realloc mistake and add null check more [\#580](https://github.com/redis/hiredis/pull/580) ([charsyam](https://github.com/charsyam))
|
||||
- Proper error reporting for connect failures [\#578](https://github.com/redis/hiredis/pull/578) ([mnunberg](https://github.com/mnunberg))
|
||||
|
||||
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
||||
|
||||
## [1.0.0-rc1](https://github.com/redis/hiredis/tree/v1.0.0-rc1) - (2020-07-29)
|
||||
|
||||
_Note: There were no changes to code between v1.0.0-rc1 and v1.0.0 so see v1.0.0 for changelog_
|
||||
|
||||
### 0.14.1 (2020-03-13)
|
||||
|
||||
* Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder)
|
||||
|
||||
### 0.14.0 (2018-09-25)
|
||||
**BREAKING CHANGES**:
|
||||
|
||||
* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well.
|
||||
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
|
||||
|
||||
* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])
|
||||
* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
|
||||
* Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622])
|
||||
* Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8])
|
||||
* Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8])
|
||||
* Fix bulk and multi-bulk length truncation (Justin Brewer [109197])
|
||||
* Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94])
|
||||
* Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6])
|
||||
* Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1])
|
||||
* Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b])
|
||||
* Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96])
|
||||
* Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234])
|
||||
* Don't send negative values to `__redisAsyncCommand` (Frederik Deweerdt [706129])
|
||||
* Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c])
|
||||
* Fix libevent leak (zfz [515228])
|
||||
* Clean up GCC warning (Ichito Nagata [2ec774])
|
||||
* Keep track of errno in `__redisSetErrorFromErrno()` as snprintf may use it (Jin Qing [25cd88])
|
||||
* Solaris compilation fix (Donald Whyte [41b07d])
|
||||
* Reorder linker arguments when building examples (Tustfarm-heart [06eedd])
|
||||
* Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999])
|
||||
* libuv use after free fix (Paul Scott [cbb956])
|
||||
* Properly close socket fd on reconnect attempt (WSL [64d1ec])
|
||||
* Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78])
|
||||
* Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5])
|
||||
* Update libevent (Chris Xin [386802])
|
||||
* Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e])
|
||||
* Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6])
|
||||
* Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3])
|
||||
* Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb])
|
||||
* Compatibility fix for strerror_r (Tom Lee [bb1747])
|
||||
* Properly detect integer parse/overflow errors (Justin Brewer [93421f])
|
||||
* Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40])
|
||||
* Catch a buffer overflow when formatting the error message
|
||||
* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13
|
||||
* Fix warnings, when compiled with -Wshadow
|
||||
* Make hiredis compile in Cygwin on Windows, now CI-tested
|
||||
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
|
||||
protocol errors. This is consistent with the RESP specification. On 32-bit
|
||||
platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
* Remove backwards compatibility macro's
|
||||
|
||||
This removes the following old function aliases, use the new name now:
|
||||
|
||||
| Old | New |
|
||||
| --------------------------- | ---------------------- |
|
||||
| redisReplyReaderCreate | redisReaderCreate |
|
||||
| redisReplyReaderCreate | redisReaderCreate |
|
||||
| redisReplyReaderFree | redisReaderFree |
|
||||
| redisReplyReaderFeed | redisReaderFeed |
|
||||
| redisReplyReaderGetReply | redisReaderGetReply |
|
||||
| redisReplyReaderSetPrivdata | redisReaderSetPrivdata |
|
||||
| redisReplyReaderGetObject | redisReaderGetObject |
|
||||
| redisReplyReaderGetError | redisReaderGetError |
|
||||
|
||||
* The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS`
|
||||
|
||||
Previously it broke some builds for people that had `DEBUG` set to some arbitrary value,
|
||||
due to debugging other software.
|
||||
By renaming we avoid unintentional name clashes.
|
||||
|
||||
Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again.
|
||||
|
||||
### 0.13.3 (2015-09-16)
|
||||
|
||||
* Revert "Clear `REDIS_CONNECTED` flag when connection is closed".
|
||||
* Make tests pass on FreeBSD (Thanks, Giacomo Olgeni)
|
||||
|
||||
|
||||
If the `REDIS_CONNECTED` flag is cleared,
|
||||
the async onDisconnect callback function will never be called.
|
||||
This causes problems as the disconnect is never reported back to the user.
|
||||
|
||||
### 0.13.2 (2015-08-25)
|
||||
|
||||
* Prevent crash on pending replies in async code (Thanks, @switch-st)
|
||||
* Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs)
|
||||
* Add MacOS X addapter (Thanks, @dizzus)
|
||||
* Add Qt adapter (Thanks, Pietro Cerutti)
|
||||
* Add Ivykis adapter (Thanks, Gergely Nagy)
|
||||
|
||||
All adapters are provided as is and are only tested where possible.
|
||||
|
||||
### 0.13.1 (2015-05-03)
|
||||
|
||||
This is a bug fix release.
|
||||
The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code.
|
||||
Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects.
|
||||
Other non-C99 code can now use hiredis as usual again.
|
||||
Sorry for the inconvenience.
|
||||
|
||||
* Fix memory leak in async reply handling (Salvatore Sanfilippo)
|
||||
* Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa)
|
||||
|
||||
### 0.13.0 (2015-04-16)
|
||||
|
||||
This release adds a minimal Windows compatibility layer.
|
||||
The parser, standalone since v0.12.0, can now be compiled on Windows
|
||||
(and thus used in other client libraries as well)
|
||||
|
||||
* Windows compatibility layer for parser code (tzickel)
|
||||
* Properly escape data printed to PKGCONF file (Dan Skorupski)
|
||||
* Fix tests when assert() undefined (Keith Bennett, Matt Stancliff)
|
||||
* Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra)
|
||||
|
||||
### 0.12.1 (2015-01-26)
|
||||
|
||||
* Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location
|
||||
* Fix `make test` as 32 bit build on 64 bit platform
|
||||
|
||||
### 0.12.0 (2015-01-22)
|
||||
|
||||
* Add optional KeepAlive support
|
||||
|
||||
* Try again on EINTR errors
|
||||
|
||||
* Add libuv adapter
|
||||
|
||||
* Add IPv6 support
|
||||
|
||||
* Remove possibility of multiple close on same fd
|
||||
|
||||
* Add ability to bind source address on connect
|
||||
|
||||
* Add redisConnectFd() and redisFreeKeepFd()
|
||||
|
||||
* Fix getaddrinfo() memory leak
|
||||
|
||||
* Free string if it is unused (fixes memory leak)
|
||||
|
||||
* Improve redisAppendCommandArgv performance 2.5x
|
||||
|
||||
* Add support for SO_REUSEADDR
|
||||
|
||||
* Fix redisvFormatCommand format parsing
|
||||
|
||||
* Add GLib 2.0 adapter
|
||||
|
||||
* Refactor reading code into read.c
|
||||
|
||||
* Fix errno error buffers to not clobber errors
|
||||
|
||||
* Generate pkgconf during build
|
||||
|
||||
* Silence _BSD_SOURCE warnings
|
||||
|
||||
* Improve digit counting for multibulk creation
|
||||
|
||||
|
||||
### 0.11.0
|
||||
|
||||
* Increase the maximum multi-bulk reply depth to 7.
|
||||
|
||||
* Increase the read buffer size from 2k to 16k.
|
||||
|
||||
* Use poll(2) instead of select(2) to support large fds (>= 1024).
|
||||
|
||||
### 0.10.1
|
||||
|
||||
* Makefile overhaul. Important to check out if you override one or more
|
||||
variables using environment variables or via arguments to the "make" tool.
|
||||
|
||||
* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements
|
||||
being created by the default reply object functions.
|
||||
|
||||
* Issue #43: Don't crash in an asynchronous context when Redis returns an error
|
||||
reply after the connection has been made (this happens when the maximum
|
||||
number of connections is reached).
|
||||
|
||||
### 0.10.0
|
||||
|
||||
* See commit log.
|
165
ext/hiredis-1.0.2/CMakeLists.txt
Normal file
165
ext/hiredis-1.0.2/CMakeLists.txt
Normal file
@ -0,0 +1,165 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.4.0)
|
||||
INCLUDE(GNUInstallDirs)
|
||||
PROJECT(hiredis)
|
||||
|
||||
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
|
||||
OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF)
|
||||
OPTION(ENABLE_SSL_TESTS, "Should we test SSL connections" OFF)
|
||||
|
||||
MACRO(getVersionBit name)
|
||||
SET(VERSION_REGEX "^#define ${name} (.+)$")
|
||||
FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredis.h"
|
||||
VERSION_BIT REGEX ${VERSION_REGEX})
|
||||
STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}")
|
||||
ENDMACRO(getVersionBit)
|
||||
|
||||
getVersionBit(HIREDIS_MAJOR)
|
||||
getVersionBit(HIREDIS_MINOR)
|
||||
getVersionBit(HIREDIS_PATCH)
|
||||
getVersionBit(HIREDIS_SONAME)
|
||||
SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}")
|
||||
MESSAGE("Detected version: ${VERSION}")
|
||||
|
||||
PROJECT(hiredis VERSION "${VERSION}")
|
||||
|
||||
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
|
||||
|
||||
SET(hiredis_sources
|
||||
alloc.c
|
||||
async.c
|
||||
dict.c
|
||||
hiredis.c
|
||||
net.c
|
||||
read.c
|
||||
sds.c
|
||||
sockcompat.c)
|
||||
|
||||
SET(hiredis_sources ${hiredis_sources})
|
||||
|
||||
IF(WIN32)
|
||||
ADD_COMPILE_DEFINITIONS(_CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN)
|
||||
ENDIF()
|
||||
|
||||
ADD_LIBRARY(hiredis SHARED ${hiredis_sources})
|
||||
|
||||
SET_TARGET_PROPERTIES(hiredis
|
||||
PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE
|
||||
VERSION "${HIREDIS_SONAME}")
|
||||
IF(WIN32 OR MINGW)
|
||||
TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
|
||||
ENDIF()
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:.> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
|
||||
CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
|
||||
|
||||
INSTALL(TARGETS hiredis
|
||||
EXPORT hiredis-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
INSTALL(FILES hiredis.h read.h sds.h async.h alloc.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(DIRECTORY adapters
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
export(EXPORT hiredis-targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis-targets.cmake"
|
||||
NAMESPACE hiredis::)
|
||||
|
||||
SET(CMAKE_CONF_INSTALL_DIR share/hiredis)
|
||||
SET(INCLUDE_INSTALL_DIR include)
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR)
|
||||
|
||||
INSTALL(EXPORT hiredis-targets
|
||||
FILE hiredis-targets.cmake
|
||||
NAMESPACE hiredis::
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
|
||||
|
||||
IF(ENABLE_SSL)
|
||||
IF (NOT OPENSSL_ROOT_DIR)
|
||||
IF (APPLE)
|
||||
SET(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
FIND_PACKAGE(OpenSSL REQUIRED)
|
||||
SET(hiredis_ssl_sources
|
||||
ssl.c)
|
||||
ADD_LIBRARY(hiredis_ssl SHARED
|
||||
${hiredis_ssl_sources})
|
||||
|
||||
IF (APPLE)
|
||||
SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup")
|
||||
ENDIF()
|
||||
|
||||
SET_TARGET_PROPERTIES(hiredis_ssl
|
||||
PROPERTIES
|
||||
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
|
||||
VERSION "${HIREDIS_SONAME}")
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
|
||||
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
|
||||
IF (WIN32 OR MINGW)
|
||||
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis)
|
||||
ENDIF()
|
||||
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
|
||||
|
||||
INSTALL(TARGETS hiredis_ssl
|
||||
EXPORT hiredis_ssl-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
INSTALL(FILES hiredis_ssl.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
export(EXPORT hiredis_ssl-targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-targets.cmake"
|
||||
NAMESPACE hiredis::)
|
||||
|
||||
SET(CMAKE_CONF_INSTALL_DIR share/hiredis_ssl)
|
||||
configure_package_config_file(hiredis_ssl-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR)
|
||||
|
||||
INSTALL(EXPORT hiredis_ssl-targets
|
||||
FILE hiredis_ssl-targets.cmake
|
||||
NAMESPACE hiredis::
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake
|
||||
DESTINATION ${CMAKE_CONF_INSTALL_DIR})
|
||||
ENDIF()
|
||||
|
||||
IF(NOT DISABLE_TESTS)
|
||||
ENABLE_TESTING()
|
||||
ADD_EXECUTABLE(hiredis-test test.c)
|
||||
IF(ENABLE_SSL_TESTS)
|
||||
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1)
|
||||
TARGET_LINK_LIBRARIES(hiredis-test hiredis hiredis_ssl)
|
||||
ELSE()
|
||||
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
|
||||
ENDIF()
|
||||
ADD_TEST(NAME hiredis-test
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
|
||||
ENDIF()
|
||||
|
||||
# Add examples
|
||||
IF(ENABLE_EXAMPLES)
|
||||
ADD_SUBDIRECTORY(examples)
|
||||
ENDIF(ENABLE_EXAMPLES)
|
29
ext/hiredis-1.0.2/COPYING
Normal file
29
ext/hiredis-1.0.2/COPYING
Normal file
@ -0,0 +1,29 @@
|
||||
Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Redis nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
308
ext/hiredis-1.0.2/Makefile
Normal file
308
ext/hiredis-1.0.2/Makefile
Normal file
@ -0,0 +1,308 @@
|
||||
# Hiredis Makefile
|
||||
# Copyright (C) 2010-2011 Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
# This file is released under the BSD license, see the COPYING file
|
||||
|
||||
OBJ=alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o
|
||||
SSL_OBJ=ssl.o
|
||||
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push
|
||||
ifeq ($(USE_SSL),1)
|
||||
EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
|
||||
endif
|
||||
TESTS=hiredis-test
|
||||
LIBNAME=libhiredis
|
||||
PKGCONFNAME=hiredis.pc
|
||||
SSL_LIBNAME=libhiredis_ssl
|
||||
SSL_PKGCONFNAME=hiredis_ssl.pc
|
||||
|
||||
HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
|
||||
HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}')
|
||||
HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}')
|
||||
HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}')
|
||||
|
||||
# Installation related variables and target
|
||||
PREFIX?=/usr/local
|
||||
INCLUDE_PATH?=include/hiredis
|
||||
LIBRARY_PATH?=lib
|
||||
PKGCONF_PATH?=pkgconfig
|
||||
INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH)
|
||||
INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH)
|
||||
INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH)
|
||||
|
||||
# redis-server configuration used for testing
|
||||
REDIS_PORT=56379
|
||||
REDIS_SERVER=redis-server
|
||||
define REDIS_TEST_CONFIG
|
||||
daemonize yes
|
||||
pidfile /tmp/hiredis-test-redis.pid
|
||||
port $(REDIS_PORT)
|
||||
bind 127.0.0.1
|
||||
unixsocket /tmp/hiredis-test-redis.sock
|
||||
endef
|
||||
export REDIS_TEST_CONFIG
|
||||
|
||||
# Fallback to gcc when $CC is not in $PATH.
|
||||
CC:=$(shell sh -c 'type $${CC%% *} >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
|
||||
CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++')
|
||||
OPTIMIZATION?=-O3
|
||||
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers
|
||||
DEBUG_FLAGS?= -g -ggdb
|
||||
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS)
|
||||
REAL_LDFLAGS=$(LDFLAGS)
|
||||
|
||||
DYLIBSUFFIX=so
|
||||
STLIBSUFFIX=a
|
||||
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
|
||||
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
|
||||
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
|
||||
|
||||
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
|
||||
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
|
||||
STLIB_MAKE_CMD=$(AR) rcs
|
||||
|
||||
SSL_DYLIB_MINOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
|
||||
SSL_DYLIB_MAJOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
|
||||
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
|
||||
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
|
||||
SSL_DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(SSL_DYLIB_MINOR_NAME)
|
||||
|
||||
# Platform-specific overrides
|
||||
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
|
||||
USE_SSL?=0
|
||||
|
||||
# This is required for test.c only
|
||||
ifeq ($(USE_SSL),1)
|
||||
CFLAGS+=-DHIREDIS_TEST_SSL
|
||||
endif
|
||||
|
||||
ifeq ($(uname_S),Linux)
|
||||
SSL_LDFLAGS=-lssl -lcrypto
|
||||
else
|
||||
OPENSSL_PREFIX?=/usr/local/opt/openssl
|
||||
CFLAGS+=-I$(OPENSSL_PREFIX)/include
|
||||
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
|
||||
endif
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
IS_SUN_CC=$(shell sh -c '$(CC) -V 2>&1 |egrep -i -c "sun|studio"')
|
||||
ifeq ($(IS_SUN_CC),1)
|
||||
SUN_SHARED_FLAG=-G
|
||||
else
|
||||
SUN_SHARED_FLAG=-shared
|
||||
endif
|
||||
REAL_LDFLAGS+= -ldl -lnsl -lsocket
|
||||
DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
|
||||
SSL_DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(SSL_DYLIBNAME) -h $(SSL_DYLIB_MINOR_NAME) $(LDFLAGS) $(SSL_LDFLAGS)
|
||||
endif
|
||||
ifeq ($(uname_S),Darwin)
|
||||
DYLIBSUFFIX=dylib
|
||||
DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX)
|
||||
DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
|
||||
SSL_DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME) -o $(SSL_DYLIBNAME) $(LDFLAGS) $(SSL_LDFLAGS)
|
||||
DYLIB_PLUGIN=-Wl,-undefined -Wl,dynamic_lookup
|
||||
endif
|
||||
|
||||
all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
|
||||
endif
|
||||
|
||||
# Deps (use make dep to generate this)
|
||||
alloc.o: alloc.c fmacros.h alloc.h
|
||||
async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h
|
||||
dict.o: dict.c fmacros.h alloc.h dict.h
|
||||
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h
|
||||
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h
|
||||
read.o: read.c fmacros.h alloc.h read.h sds.h win32.h
|
||||
sds.o: sds.c sds.h sdsalloc.h alloc.h
|
||||
sockcompat.o: sockcompat.c sockcompat.h
|
||||
ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h
|
||||
test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h sockcompat.h win32.h
|
||||
|
||||
$(DYLIBNAME): $(OBJ)
|
||||
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)
|
||||
|
||||
$(STLIBNAME): $(OBJ)
|
||||
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)
|
||||
|
||||
$(SSL_DYLIBNAME): $(SSL_OBJ)
|
||||
$(SSL_DYLIB_MAKE_CMD) $(DYLIB_PLUGIN) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
$(SSL_STLIBNAME): $(SSL_OBJ)
|
||||
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ)
|
||||
|
||||
dynamic: $(DYLIBNAME)
|
||||
static: $(STLIBNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
dynamic: $(SSL_DYLIBNAME)
|
||||
static: $(SSL_STLIBNAME)
|
||||
endif
|
||||
|
||||
# Binaries:
|
||||
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)
|
||||
|
||||
|
||||
ifndef AE_DIR
|
||||
hiredis-example-ae:
|
||||
@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
|
||||
@false
|
||||
else
|
||||
hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME)
|
||||
endif
|
||||
|
||||
ifndef LIBUV_DIR
|
||||
hiredis-example-libuv:
|
||||
@echo "Please specify LIBUV_DIR (e.g. ../libuv/)"
|
||||
@false
|
||||
else
|
||||
hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
endif
|
||||
|
||||
ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),)
|
||||
hiredis-example-qt:
|
||||
@echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR"
|
||||
@false
|
||||
else
|
||||
hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME)
|
||||
$(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \
|
||||
$(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore
|
||||
$(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \
|
||||
$(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore
|
||||
$(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore
|
||||
endif
|
||||
|
||||
hiredis-example: examples/example.c $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
hiredis-example-push: examples/example-push.c $(STLIBNAME)
|
||||
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)
|
||||
|
||||
examples: $(EXAMPLES)
|
||||
|
||||
TEST_LIBS = $(STLIBNAME)
|
||||
ifeq ($(USE_SSL),1)
|
||||
TEST_LIBS += $(SSL_STLIBNAME)
|
||||
TEST_LDFLAGS = $(SSL_LDFLAGS) -lssl -lcrypto -lpthread
|
||||
endif
|
||||
|
||||
hiredis-test: test.o $(TEST_LIBS)
|
||||
$(CC) -o $@ $(REAL_CFLAGS) -I. $^ $(REAL_LDFLAGS) $(TEST_LDFLAGS)
|
||||
|
||||
hiredis-%: %.o $(STLIBNAME)
|
||||
$(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS)
|
||||
|
||||
test: hiredis-test
|
||||
./hiredis-test
|
||||
|
||||
check: hiredis-test
|
||||
TEST_SSL=$(USE_SSL) ./test.sh
|
||||
|
||||
.c.o:
|
||||
$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
|
||||
|
||||
dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c
|
||||
|
||||
INSTALL?= cp -pPR
|
||||
|
||||
$(PKGCONFNAME): hiredis.h
|
||||
@echo "Generating $@ for pkgconfig..."
|
||||
@echo prefix=$(PREFIX) > $@
|
||||
@echo exec_prefix=\$${prefix} >> $@
|
||||
@echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
|
||||
@echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
|
||||
@echo >> $@
|
||||
@echo Name: hiredis >> $@
|
||||
@echo Description: Minimalistic C client library for Redis. >> $@
|
||||
@echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
|
||||
@echo Libs: -L\$${libdir} -lhiredis >> $@
|
||||
@echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
|
||||
|
||||
$(SSL_PKGCONFNAME): hiredis_ssl.h
|
||||
@echo "Generating $@ for pkgconfig..."
|
||||
@echo prefix=$(PREFIX) > $@
|
||||
@echo exec_prefix=\$${prefix} >> $@
|
||||
@echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
|
||||
@echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
|
||||
@echo >> $@
|
||||
@echo Name: hiredis_ssl >> $@
|
||||
@echo Description: SSL Support for hiredis. >> $@
|
||||
@echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
|
||||
@echo Requires: hiredis >> $@
|
||||
@echo Libs: -L\$${libdir} -lhiredis_ssl >> $@
|
||||
@echo Libs.private: -lssl -lcrypto >> $@
|
||||
|
||||
install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
|
||||
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
|
||||
$(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH)
|
||||
$(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters
|
||||
$(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
|
||||
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME)
|
||||
$(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH)
|
||||
mkdir -p $(INSTALL_PKGCONF_PATH)
|
||||
$(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
|
||||
|
||||
ifeq ($(USE_SSL),1)
|
||||
install: install-ssl
|
||||
|
||||
install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
|
||||
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
|
||||
$(INSTALL) hiredis_ssl.h $(INSTALL_INCLUDE_PATH)
|
||||
$(INSTALL) $(SSL_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME)
|
||||
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIBNAME)
|
||||
$(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH)
|
||||
mkdir -p $(INSTALL_PKGCONF_PATH)
|
||||
$(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
|
||||
endif
|
||||
|
||||
32bit:
|
||||
@echo ""
|
||||
@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"
|
||||
@echo ""
|
||||
$(MAKE) CFLAGS="-m32" LDFLAGS="-m32"
|
||||
|
||||
32bit-vars:
|
||||
$(eval CFLAGS=-m32)
|
||||
$(eval LDFLAGS=-m32)
|
||||
|
||||
gprof:
|
||||
$(MAKE) CFLAGS="-pg" LDFLAGS="-pg"
|
||||
|
||||
gcov:
|
||||
$(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs"
|
||||
|
||||
coverage: gcov
|
||||
make check
|
||||
mkdir -p tmp/lcov
|
||||
lcov -d . -c -o tmp/lcov/hiredis.info
|
||||
genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info
|
||||
|
||||
noopt:
|
||||
$(MAKE) OPTIMIZATION=""
|
||||
|
||||
.PHONY: all test check clean dep install 32bit 32bit-vars gprof gcov noopt
|
664
ext/hiredis-1.0.2/README.md
Normal file
664
ext/hiredis-1.0.2/README.md
Normal file
@ -0,0 +1,664 @@
|
||||
[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)
|
||||
|
||||
**This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).**
|
||||
|
||||
# HIREDIS
|
||||
|
||||
Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database.
|
||||
|
||||
It is minimalistic because it just adds minimal support for the protocol, but
|
||||
at the same time it uses a high level printf-alike API in order to make it
|
||||
much higher level than otherwise suggested by its minimal code base and the
|
||||
lack of explicit bindings for every Redis command.
|
||||
|
||||
Apart from supporting sending commands and receiving replies, it comes with
|
||||
a reply parser that is decoupled from the I/O layer. It
|
||||
is a stream parser designed for easy reusability, which can for instance be used
|
||||
in higher level language bindings for efficient reply parsing.
|
||||
|
||||
Hiredis only supports the binary-safe Redis protocol, so you can use it with any
|
||||
Redis version >= 1.2.0.
|
||||
|
||||
The library comes with multiple APIs. There is the
|
||||
*synchronous API*, the *asynchronous API* and the *reply parsing API*.
|
||||
|
||||
## Upgrading to `1.0.2`
|
||||
|
||||
<span style="color:red">NOTE: v1.0.1 erroneously bumped SONAME, which is why it is skipped here.</span>
|
||||
|
||||
Version 1.0.2 is simply 1.0.0 with a fix for [CVE-2021-32765](https://github.com/redis/hiredis/security/advisories/GHSA-hfm9-39pp-55p2). They are otherwise identical.
|
||||
|
||||
## Upgrading to `1.0.0`
|
||||
|
||||
Version 1.0.0 marks the first stable release of Hiredis.
|
||||
It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.
|
||||
It also bundles the updated `sds` library, to sync up with upstream and Redis.
|
||||
For code changes see the [Changelog](CHANGELOG.md).
|
||||
|
||||
_Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._
|
||||
|
||||
## IMPORTANT: Breaking changes from `0.14.1` -> `1.0.0`
|
||||
|
||||
* `redisContext` has two additional members (`free_privdata`, and `privctx`).
|
||||
* `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`.
|
||||
* `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter.
|
||||
|
||||
## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x
|
||||
|
||||
Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
|
||||
protocol errors. This is consistent with the RESP specification. On 32-bit
|
||||
platforms, the upper bound is lowered to `SIZE_MAX`.
|
||||
|
||||
Change `redisReply.len` to `size_t`, as it denotes the the size of a string
|
||||
|
||||
User code should compare this to `size_t` values as well. If it was used to
|
||||
compare to other values, casting might be necessary or can be removed, if
|
||||
casting was applied before.
|
||||
|
||||
## Upgrading from `<0.9.0`
|
||||
|
||||
Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
|
||||
code using hiredis should not be a big pain. The key thing to keep in mind when
|
||||
upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to
|
||||
the stateless 0.0.1 that only has a file descriptor to work with.
|
||||
|
||||
## Synchronous API
|
||||
|
||||
To consume the synchronous API, there are only a few function calls that need to be introduced:
|
||||
|
||||
```c
|
||||
redisContext *redisConnect(const char *ip, int port);
|
||||
void *redisCommand(redisContext *c, const char *format, ...);
|
||||
void freeReplyObject(void *reply);
|
||||
```
|
||||
|
||||
### Connecting
|
||||
|
||||
The function `redisConnect` is used to create a so-called `redisContext`. The
|
||||
context is where Hiredis holds state for a connection. The `redisContext`
|
||||
struct has an integer `err` field that is non-zero when the connection is in
|
||||
an error state. The field `errstr` will contain a string with a description of
|
||||
the error. More information on errors can be found in the **Errors** section.
|
||||
After trying to connect to Redis using `redisConnect` you should
|
||||
check the `err` field to see if establishing the connection was successful:
|
||||
```c
|
||||
redisContext *c = redisConnect("127.0.0.1", 6379);
|
||||
if (c == NULL || c->err) {
|
||||
if (c) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
// handle error
|
||||
} else {
|
||||
printf("Can't allocate redis context\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
*Note: A `redisContext` is not thread-safe.*
|
||||
|
||||
### Sending commands
|
||||
|
||||
There are several ways to issue commands to Redis. The first that will be introduced is
|
||||
`redisCommand`. This function takes a format similar to printf. In the simplest form,
|
||||
it is used like this:
|
||||
```c
|
||||
reply = redisCommand(context, "SET foo bar");
|
||||
```
|
||||
|
||||
The specifier `%s` interpolates a string in the command, and uses `strlen` to
|
||||
determine the length of the string:
|
||||
```c
|
||||
reply = redisCommand(context, "SET foo %s", value);
|
||||
```
|
||||
When you need to pass binary safe strings in a command, the `%b` specifier can be
|
||||
used. Together with a pointer to the string, it requires a `size_t` length argument
|
||||
of the string:
|
||||
```c
|
||||
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
|
||||
```
|
||||
Internally, Hiredis splits the command in different arguments and will
|
||||
convert it to the protocol used to communicate with Redis.
|
||||
One or more spaces separates arguments, so you can use the specifiers
|
||||
anywhere in an argument:
|
||||
```c
|
||||
reply = redisCommand(context, "SET key:%s %s", myid, value);
|
||||
```
|
||||
|
||||
### Using replies
|
||||
|
||||
The return value of `redisCommand` holds a reply when the command was
|
||||
successfully executed. When an error occurs, the return value is `NULL` and
|
||||
the `err` field in the context will be set (see section on **Errors**).
|
||||
Once an error is returned the context cannot be reused and you should set up
|
||||
a new connection.
|
||||
|
||||
The standard replies that `redisCommand` are of the type `redisReply`. The
|
||||
`type` field in the `redisReply` should be used to test what kind of reply
|
||||
was received:
|
||||
|
||||
### RESP2
|
||||
|
||||
* **`REDIS_REPLY_STATUS`**:
|
||||
* The command replied with a status reply. The status string can be accessed using `reply->str`.
|
||||
The length of this string can be accessed using `reply->len`.
|
||||
|
||||
* **`REDIS_REPLY_ERROR`**:
|
||||
* The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`.
|
||||
|
||||
* **`REDIS_REPLY_INTEGER`**:
|
||||
* The command replied with an integer. The integer value can be accessed using the
|
||||
`reply->integer` field of type `long long`.
|
||||
|
||||
* **`REDIS_REPLY_NIL`**:
|
||||
* The command replied with a **nil** object. There is no data to access.
|
||||
|
||||
* **`REDIS_REPLY_STRING`**:
|
||||
* A bulk (string) reply. The value of the reply can be accessed using `reply->str`.
|
||||
The length of this string can be accessed using `reply->len`.
|
||||
|
||||
* **`REDIS_REPLY_ARRAY`**:
|
||||
* A multi bulk reply. The number of elements in the multi bulk reply is stored in
|
||||
`reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
|
||||
and can be accessed via `reply->element[..index..]`.
|
||||
Redis may reply with nested arrays but this is fully supported.
|
||||
|
||||
### RESP3
|
||||
|
||||
Hiredis also supports every new `RESP3` data type which are as follows. For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md)
|
||||
|
||||
* **`REDIS_REPLY_DOUBLE`**:
|
||||
* The command replied with a double-precision floating point number.
|
||||
The value is stored as a string in the `str` member, and can be converted with `strtod` or similar.
|
||||
|
||||
* **`REDIS_REPLY_BOOL`**:
|
||||
* A boolean true/false reply.
|
||||
The value is stored in the `integer` member and will be either `0` or `1`.
|
||||
|
||||
* **`REDIS_REPLY_MAP`**:
|
||||
* An array with the added invariant that there will always be an even number of elements.
|
||||
The MAP is functionally equivelant to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.
|
||||
|
||||
* **`REDIS_REPLY_SET`**:
|
||||
* An array response where each entry is unique.
|
||||
Like the MAP type, the data is identical to an array response except there are no duplicate values.
|
||||
|
||||
* **`REDIS_REPLY_PUSH`**:
|
||||
* An array that can be generated spontaneously by Redis.
|
||||
This array response will always contain at least two subelements. The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself.
|
||||
|
||||
* **`REDIS_REPLY_ATTR`**:
|
||||
* An array structurally identical to a `MAP` but intended as meta-data about a reply.
|
||||
_As of Redis 6.0.6 this reply type is not used in Redis_
|
||||
|
||||
* **`REDIS_REPLY_BIGNUM`**:
|
||||
* A string representing an arbitrarily large signed or unsigned integer value.
|
||||
The number will be encoded as a string in the `str` member of `redisReply`.
|
||||
|
||||
* **`REDIS_REPLY_VERB`**:
|
||||
* A verbatim string, intended to be presented to the user without modification.
|
||||
The string payload is stored in the `str` memeber, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown).
|
||||
|
||||
Replies should be freed using the `freeReplyObject()` function.
|
||||
Note that this function will take care of freeing sub-reply objects
|
||||
contained in arrays and nested arrays, so there is no need for the user to
|
||||
free the sub replies (it is actually harmful and will corrupt the memory).
|
||||
|
||||
**Important:** the current version of hiredis (1.0.0) frees replies when the
|
||||
asynchronous API is used. This means you should not call `freeReplyObject` when
|
||||
you use this API. The reply is cleaned up by hiredis _after_ the callback
|
||||
returns. We may introduce a flag to make this configurable in future versions of the library.
|
||||
|
||||
### Cleaning up
|
||||
|
||||
To disconnect and free the context the following function can be used:
|
||||
```c
|
||||
void redisFree(redisContext *c);
|
||||
```
|
||||
This function immediately closes the socket and then frees the allocations done in
|
||||
creating the context.
|
||||
|
||||
### Sending commands (cont'd)
|
||||
|
||||
Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
|
||||
It has the following prototype:
|
||||
```c
|
||||
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
```
|
||||
It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
|
||||
arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
|
||||
use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
|
||||
need to be binary safe, the entire array of lengths `argvlen` should be provided.
|
||||
|
||||
The return value has the same semantic as `redisCommand`.
|
||||
|
||||
### Pipelining
|
||||
|
||||
To explain how Hiredis supports pipelining in a blocking connection, there needs to be
|
||||
understanding of the internal execution flow.
|
||||
|
||||
When any of the functions in the `redisCommand` family is called, Hiredis first formats the
|
||||
command according to the Redis protocol. The formatted command is then put in the output buffer
|
||||
of the context. This output buffer is dynamic, so it can hold any number of commands.
|
||||
After the command is put in the output buffer, `redisGetReply` is called. This function has the
|
||||
following two execution paths:
|
||||
|
||||
1. The input buffer is non-empty:
|
||||
* Try to parse a single reply from the input buffer and return it
|
||||
* If no reply could be parsed, continue at *2*
|
||||
2. The input buffer is empty:
|
||||
* Write the **entire** output buffer to the socket
|
||||
* Read from the socket until a single reply could be parsed
|
||||
|
||||
The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply
|
||||
is expected on the socket. To pipeline commands, the only things that needs to be done is
|
||||
filling up the output buffer. For this cause, two commands can be used that are identical
|
||||
to the `redisCommand` family, apart from not returning a reply:
|
||||
```c
|
||||
void redisAppendCommand(redisContext *c, const char *format, ...);
|
||||
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
```
|
||||
After calling either function one or more times, `redisGetReply` can be used to receive the
|
||||
subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where
|
||||
the latter means an error occurred while reading a reply. Just as with the other commands,
|
||||
the `err` field in the context can be used to find out what the cause of this error is.
|
||||
|
||||
The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
|
||||
a single call to `read(2)`):
|
||||
```c
|
||||
redisReply *reply;
|
||||
redisAppendCommand(context,"SET foo bar");
|
||||
redisAppendCommand(context,"GET foo");
|
||||
redisGetReply(context,(void *)&reply); // reply for SET
|
||||
freeReplyObject(reply);
|
||||
redisGetReply(context,(void *)&reply); // reply for GET
|
||||
freeReplyObject(reply);
|
||||
```
|
||||
This API can also be used to implement a blocking subscriber:
|
||||
```c
|
||||
reply = redisCommand(context,"SUBSCRIBE foo");
|
||||
freeReplyObject(reply);
|
||||
while(redisGetReply(context,(void *)&reply) == REDIS_OK) {
|
||||
// consume message
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
```
|
||||
### Errors
|
||||
|
||||
When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
|
||||
returned. The `err` field inside the context will be non-zero and set to one of the
|
||||
following constants:
|
||||
|
||||
* **`REDIS_ERR_IO`**:
|
||||
There was an I/O error while creating the connection, trying to write
|
||||
to the socket or read from the socket. If you included `errno.h` in your
|
||||
application, you can use the global `errno` variable to find out what is
|
||||
wrong.
|
||||
|
||||
* **`REDIS_ERR_EOF`**:
|
||||
The server closed the connection which resulted in an empty read.
|
||||
|
||||
* **`REDIS_ERR_PROTOCOL`**:
|
||||
There was an error while parsing the protocol.
|
||||
|
||||
* **`REDIS_ERR_OTHER`**:
|
||||
Any other error. Currently, it is only used when a specified hostname to connect
|
||||
to cannot be resolved.
|
||||
|
||||
In every case, the `errstr` field in the context will be set to hold a string representation
|
||||
of the error.
|
||||
|
||||
## Asynchronous API
|
||||
|
||||
Hiredis comes with an asynchronous API that works easily with any event library.
|
||||
Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html)
|
||||
and [libevent](http://monkey.org/~provos/libevent/).
|
||||
|
||||
### Connecting
|
||||
|
||||
The function `redisAsyncConnect` can be used to establish a non-blocking connection to
|
||||
Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field
|
||||
should be checked after creation to see if there were errors creating the connection.
|
||||
Because the connection that will be created is non-blocking, the kernel is not able to
|
||||
instantly return if the specified host and port is able to accept a connection.
|
||||
|
||||
*Note: A `redisAsyncContext` is not thread-safe.*
|
||||
|
||||
```c
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
The asynchronous context can hold a disconnect callback function that is called when the
|
||||
connection is disconnected (either because of an error or per user request). This function should
|
||||
have the following prototype:
|
||||
```c
|
||||
void(const redisAsyncContext *c, int status);
|
||||
```
|
||||
On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
|
||||
user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
|
||||
field in the context can be accessed to find out the cause of the error.
|
||||
|
||||
The context object is always freed after the disconnect callback fired. When a reconnect is needed,
|
||||
the disconnect callback is a good point to do so.
|
||||
|
||||
Setting the disconnect callback can only be done once per context. For subsequent calls it will
|
||||
return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
|
||||
```c
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
```
|
||||
`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.
|
||||
### Sending commands and their callbacks
|
||||
|
||||
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
|
||||
Therefore, unlike the synchronous API, there is only a single way to send commands.
|
||||
Because commands are sent to Redis asynchronously, issuing a command requires a callback function
|
||||
that is called when the reply is received. Reply callbacks should have the following prototype:
|
||||
```c
|
||||
void(redisAsyncContext *c, void *reply, void *privdata);
|
||||
```
|
||||
The `privdata` argument can be used to curry arbitrary data to the callback from the point where
|
||||
the command is initially queued for execution.
|
||||
|
||||
The functions that can be used to issue commands in an asynchronous context are:
|
||||
```c
|
||||
int redisAsyncCommand(
|
||||
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
|
||||
const char *format, ...);
|
||||
int redisAsyncCommandArgv(
|
||||
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
|
||||
int argc, const char **argv, const size_t *argvlen);
|
||||
```
|
||||
Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command
|
||||
was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection
|
||||
is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is
|
||||
returned on calls to the `redisAsyncCommand` family.
|
||||
|
||||
If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback
|
||||
for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only
|
||||
valid for the duration of the callback.
|
||||
|
||||
All pending callbacks are called with a `NULL` reply when the context encountered an error.
|
||||
|
||||
### Disconnecting
|
||||
|
||||
An asynchronous connection can be terminated using:
|
||||
```c
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
```
|
||||
When this function is called, the connection is **not** immediately terminated. Instead, new
|
||||
commands are no longer accepted and the connection is only terminated when all pending commands
|
||||
have been written to the socket, their respective replies have been read and their respective
|
||||
callbacks have been executed. After this, the disconnection callback is executed with the
|
||||
`REDIS_OK` status and the context object is freed.
|
||||
|
||||
### Hooking it up to event library *X*
|
||||
|
||||
There are a few hooks that need to be set on the context object after it is created.
|
||||
See the `adapters/` directory for bindings to *libev* and *libevent*.
|
||||
|
||||
## Reply parsing API
|
||||
|
||||
Hiredis comes with a reply parsing API that makes it easy for writing higher
|
||||
level language bindings.
|
||||
|
||||
The reply parsing API consists of the following functions:
|
||||
```c
|
||||
redisReader *redisReaderCreate(void);
|
||||
void redisReaderFree(redisReader *reader);
|
||||
int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
|
||||
int redisReaderGetReply(redisReader *reader, void **reply);
|
||||
```
|
||||
The same set of functions are used internally by hiredis when creating a
|
||||
normal Redis context, the above API just exposes it to the user for a direct
|
||||
usage.
|
||||
|
||||
### Usage
|
||||
|
||||
The function `redisReaderCreate` creates a `redisReader` structure that holds a
|
||||
buffer with unparsed data and state for the protocol parser.
|
||||
|
||||
Incoming data -- most likely from a socket -- can be placed in the internal
|
||||
buffer of the `redisReader` using `redisReaderFeed`. This function will make a
|
||||
copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed
|
||||
when `redisReaderGetReply` is called. This function returns an integer status
|
||||
and a reply object (as described above) via `void **reply`. The returned status
|
||||
can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went
|
||||
wrong (either a protocol error, or an out of memory error).
|
||||
|
||||
The parser limits the level of nesting for multi bulk payloads to 7. If the
|
||||
multi bulk nesting level is higher than this, the parser returns an error.
|
||||
|
||||
### Customizing replies
|
||||
|
||||
The function `redisReaderGetReply` creates `redisReply` and makes the function
|
||||
argument `reply` point to the created `redisReply` variable. For instance, if
|
||||
the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply`
|
||||
will hold the status as a vanilla C string. However, the functions that are
|
||||
responsible for creating instances of the `redisReply` can be customized by
|
||||
setting the `fn` field on the `redisReader` struct. This should be done
|
||||
immediately after creating the `redisReader`.
|
||||
|
||||
For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c)
|
||||
uses customized reply object functions to create Ruby objects.
|
||||
|
||||
### Reader max buffer
|
||||
|
||||
Both when using the Reader API directly or when using it indirectly via a
|
||||
normal Redis context, the redisReader structure uses a buffer in order to
|
||||
accumulate data from the server.
|
||||
Usually this buffer is destroyed when it is empty and is larger than 16
|
||||
KiB in order to avoid wasting memory in unused buffers
|
||||
|
||||
However when working with very big payloads destroying the buffer may slow
|
||||
down performances considerably, so it is possible to modify the max size of
|
||||
an idle buffer changing the value of the `maxbuf` field of the reader structure
|
||||
to the desired value. The special value of 0 means that there is no maximum
|
||||
value for an idle buffer, so the buffer will never get freed.
|
||||
|
||||
For instance if you have a normal Redis context you can set the maximum idle
|
||||
buffer to zero (unlimited) just with:
|
||||
```c
|
||||
context->reader->maxbuf = 0;
|
||||
```
|
||||
This should be done only in order to maximize performances when working with
|
||||
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
|
||||
as soon as possible in order to prevent allocation of useless memory.
|
||||
|
||||
### Reader max array elements
|
||||
|
||||
By default the hiredis reply parser sets the maximum number of multi-bulk elements
|
||||
to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies
|
||||
with more than this many elements you can set the value higher or to zero, meaning
|
||||
unlimited with:
|
||||
```c
|
||||
context->reader->maxelements = 0;
|
||||
```
|
||||
|
||||
## SSL/TLS Support
|
||||
|
||||
### Building
|
||||
|
||||
SSL/TLS support is not built by default and requires an explicit flag:
|
||||
|
||||
make USE_SSL=1
|
||||
|
||||
This requires OpenSSL development package (e.g. including header files to be
|
||||
available.
|
||||
|
||||
When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and
|
||||
`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries
|
||||
unaffected so no additional dependencies are introduced.
|
||||
|
||||
### Using it
|
||||
|
||||
First, you'll need to make sure you include the SSL header file:
|
||||
|
||||
```c
|
||||
#include "hiredis.h"
|
||||
#include "hiredis_ssl.h"
|
||||
```
|
||||
|
||||
You will also need to link against `libhiredis_ssl`, **in addition** to
|
||||
`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies.
|
||||
|
||||
Hiredis implements SSL/TLS on top of its normal `redisContext` or
|
||||
`redisAsyncContext`, so you will need to establish a connection first and then
|
||||
initiate an SSL/TLS handshake.
|
||||
|
||||
#### Hiredis OpenSSL Wrappers
|
||||
|
||||
Before Hiredis can negotiate an SSL/TLS connection, it is necessary to
|
||||
initialize OpenSSL and create a context. You can do that in two ways:
|
||||
|
||||
1. Work directly with the OpenSSL API to initialize the library's global context
|
||||
and create `SSL_CTX *` and `SSL *` contexts. With an `SSL *` object you can
|
||||
call `redisInitiateSSL()`.
|
||||
2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a
|
||||
`redisSSLContext` object to hold configuration and use
|
||||
`redisInitiateSSLWithContext()` to initiate the SSL/TLS handshake.
|
||||
|
||||
```c
|
||||
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
|
||||
* many contexts.
|
||||
*/
|
||||
redisSSLContext *ssl;
|
||||
|
||||
/* An error variable to indicate what went wrong, if the context fails to
|
||||
* initialize.
|
||||
*/
|
||||
redisSSLContextError ssl_error;
|
||||
|
||||
/* Initialize global OpenSSL state.
|
||||
*
|
||||
* You should call this only once when your app initializes, and only if
|
||||
* you don't explicitly or implicitly initialize OpenSSL it elsewhere.
|
||||
*/
|
||||
redisInitOpenSSL();
|
||||
|
||||
/* Create SSL context */
|
||||
ssl = redisCreateSSLContext(
|
||||
"cacertbundle.crt", /* File name of trusted CA/ca bundle file, optional */
|
||||
"/path/to/certs", /* Path of trusted certificates, optional */
|
||||
"client_cert.pem", /* File name of client certificate file, optional */
|
||||
"client_key.pem", /* File name of client private key, optional */
|
||||
"redis.mydomain.com", /* Server name to request (SNI), optional */
|
||||
&ssl_error
|
||||
) != REDIS_OK) {
|
||||
printf("SSL error: %s\n", redisSSLContextGetError(ssl_error);
|
||||
/* Abort... */
|
||||
}
|
||||
|
||||
/* Create Redis context and establish connection */
|
||||
c = redisConnect("localhost", 6443);
|
||||
if (c == NULL || c->err) {
|
||||
/* Handle error and abort... */
|
||||
}
|
||||
|
||||
/* Negotiate SSL/TLS */
|
||||
if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
|
||||
/* Handle error, in c->err / c->errstr */
|
||||
}
|
||||
```
|
||||
|
||||
## RESP3 PUSH replies
|
||||
Redis 6.0 introduced PUSH replies with the reply-type `>`. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.
|
||||
|
||||
### Default behavior
|
||||
Hiredis installs handlers on `redisContext` and `redisAsyncContext` by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to `RESP3`.
|
||||
|
||||
### Custom PUSH handler prototypes
|
||||
The callback prototypes differ between `redisContext` and `redisAsyncContext`.
|
||||
|
||||
#### redisContext
|
||||
```c
|
||||
void my_push_handler(void *privdata, void *reply) {
|
||||
/* Handle the reply */
|
||||
|
||||
/* Note: We need to free the reply in our custom handler for
|
||||
blocking contexts. This lets us keep the reply if
|
||||
we want. */
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
```
|
||||
|
||||
#### redisAsyncContext
|
||||
```c
|
||||
void my_async_push_handler(redisAsyncContext *ac, void *reply) {
|
||||
/* Handle the reply */
|
||||
|
||||
/* Note: Because async hiredis always frees replies, you should
|
||||
not call freeReplyObject in an async push callback. */
|
||||
}
|
||||
```
|
||||
|
||||
### Installing a custom handler
|
||||
There are two ways to set your own PUSH handlers.
|
||||
|
||||
1. Set `push_cb` or `async_push_cb` in the `redisOptions` struct and connect with `redisConnectWithOptions` or `redisAsyncConnectWithOptions`.
|
||||
```c
|
||||
redisOptions = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
options->push_cb = my_push_handler;
|
||||
redisContext *context = redisConnectWithOptions(&options);
|
||||
```
|
||||
2. Call `redisSetPushCallback` or `redisAsyncSetPushCallback` on a connected context.
|
||||
```c
|
||||
redisContext *context = redisConnect("127.0.0.1", 6379);
|
||||
redisSetPushCallback(context, my_push_handler);
|
||||
```
|
||||
|
||||
_Note `redisSetPushCallback` and `redisAsyncSetPushCallback` both return any currently configured handler, making it easy to override and then return to the old value._
|
||||
|
||||
### Specifying no handler
|
||||
If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways.
|
||||
1. Set the `REDIS_OPT_NO_PUSH_AUTOFREE` flag in `redisOptions` and leave the callback function pointer `NULL`.
|
||||
```c
|
||||
redisOptions = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
options->options |= REDIS_OPT_NO_PUSH_AUTOFREE;
|
||||
redisContext *context = redisConnectWithOptions(&options);
|
||||
```
|
||||
3. Call `redisSetPushCallback` with `NULL` once connected.
|
||||
```c
|
||||
redisContext *context = redisConnect("127.0.0.1", 6379);
|
||||
redisSetPushCallback(context, NULL);
|
||||
```
|
||||
|
||||
_Note: With no handler configured, calls to `redisCommand` may generate more than one reply, so this strategy is only applicable when there's some kind of blocking`redisGetReply()` loop (e.g. `MONITOR` or `SUBSCRIBE` workloads)._
|
||||
|
||||
## Allocator injection
|
||||
|
||||
Hiredis uses a pass-thru structure of function pointers defined in [alloc.h](https://github.com/redis/hiredis/blob/f5d25850/alloc.h#L41) that contain the currently configured allocation and deallocation functions. By default they just point to libc (`malloc`, `calloc`, `realloc`, etc).
|
||||
|
||||
### Overriding
|
||||
|
||||
One can override the allocators like so:
|
||||
|
||||
```c
|
||||
hiredisAllocFuncs myfuncs = {
|
||||
.mallocFn = my_malloc,
|
||||
.callocFn = my_calloc,
|
||||
.reallocFn = my_realloc,
|
||||
.strdupFn = my_strdup,
|
||||
.freeFn = my_free,
|
||||
};
|
||||
|
||||
// Override allocators (function returns current allocators if needed)
|
||||
hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs);
|
||||
```
|
||||
|
||||
To reset the allocators to their default libc function simply call:
|
||||
|
||||
```c
|
||||
hiredisResetAllocators();
|
||||
```
|
||||
|
||||
## AUTHORS
|
||||
|
||||
Salvatore Sanfilippo (antirez at gmail),\
|
||||
Pieter Noordhuis (pcnoordhuis at gmail)\
|
||||
Michael Grunder (michael dot grunder at gmail)
|
||||
|
||||
_Hiredis is released under the BSD license._
|
130
ext/hiredis-1.0.2/adapters/ae.h
Normal file
130
ext/hiredis-1.0.2/adapters/ae.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_AE_H__
|
||||
#define __HIREDIS_AE_H__
|
||||
#include <sys/types.h>
|
||||
#include <ae.h>
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
typedef struct redisAeEvents {
|
||||
redisAsyncContext *context;
|
||||
aeEventLoop *loop;
|
||||
int fd;
|
||||
int reading, writing;
|
||||
} redisAeEvents;
|
||||
|
||||
static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
((void)el); ((void)fd); ((void)mask);
|
||||
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
redisAsyncHandleRead(e->context);
|
||||
}
|
||||
|
||||
static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
((void)el); ((void)fd); ((void)mask);
|
||||
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
redisAsyncHandleWrite(e->context);
|
||||
}
|
||||
|
||||
static void redisAeAddRead(void *privdata) {
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
aeEventLoop *loop = e->loop;
|
||||
if (!e->reading) {
|
||||
e->reading = 1;
|
||||
aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisAeDelRead(void *privdata) {
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
aeEventLoop *loop = e->loop;
|
||||
if (e->reading) {
|
||||
e->reading = 0;
|
||||
aeDeleteFileEvent(loop,e->fd,AE_READABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisAeAddWrite(void *privdata) {
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
aeEventLoop *loop = e->loop;
|
||||
if (!e->writing) {
|
||||
e->writing = 1;
|
||||
aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisAeDelWrite(void *privdata) {
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
aeEventLoop *loop = e->loop;
|
||||
if (e->writing) {
|
||||
e->writing = 0;
|
||||
aeDeleteFileEvent(loop,e->fd,AE_WRITABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisAeCleanup(void *privdata) {
|
||||
redisAeEvents *e = (redisAeEvents*)privdata;
|
||||
redisAeDelRead(privdata);
|
||||
redisAeDelWrite(privdata);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisAeEvents *e;
|
||||
|
||||
/* Nothing should be attached when something is already attached */
|
||||
if (ac->ev.data != NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisAeEvents*)hi_malloc(sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
e->loop = loop;
|
||||
e->fd = c->fd;
|
||||
e->reading = e->writing = 0;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
ac->ev.addRead = redisAeAddRead;
|
||||
ac->ev.delRead = redisAeDelRead;
|
||||
ac->ev.addWrite = redisAeAddWrite;
|
||||
ac->ev.delWrite = redisAeDelWrite;
|
||||
ac->ev.cleanup = redisAeCleanup;
|
||||
ac->ev.data = e;
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif
|
156
ext/hiredis-1.0.2/adapters/glib.h
Normal file
156
ext/hiredis-1.0.2/adapters/glib.h
Normal file
@ -0,0 +1,156 @@
|
||||
#ifndef __HIREDIS_GLIB_H__
|
||||
#define __HIREDIS_GLIB_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSource source;
|
||||
redisAsyncContext *ac;
|
||||
GPollFD poll_fd;
|
||||
} RedisSource;
|
||||
|
||||
static void
|
||||
redis_source_add_read (gpointer data)
|
||||
{
|
||||
RedisSource *source = (RedisSource *)data;
|
||||
g_return_if_fail(source);
|
||||
source->poll_fd.events |= G_IO_IN;
|
||||
g_main_context_wakeup(g_source_get_context((GSource *)data));
|
||||
}
|
||||
|
||||
static void
|
||||
redis_source_del_read (gpointer data)
|
||||
{
|
||||
RedisSource *source = (RedisSource *)data;
|
||||
g_return_if_fail(source);
|
||||
source->poll_fd.events &= ~G_IO_IN;
|
||||
g_main_context_wakeup(g_source_get_context((GSource *)data));
|
||||
}
|
||||
|
||||
static void
|
||||
redis_source_add_write (gpointer data)
|
||||
{
|
||||
RedisSource *source = (RedisSource *)data;
|
||||
g_return_if_fail(source);
|
||||
source->poll_fd.events |= G_IO_OUT;
|
||||
g_main_context_wakeup(g_source_get_context((GSource *)data));
|
||||
}
|
||||
|
||||
static void
|
||||
redis_source_del_write (gpointer data)
|
||||
{
|
||||
RedisSource *source = (RedisSource *)data;
|
||||
g_return_if_fail(source);
|
||||
source->poll_fd.events &= ~G_IO_OUT;
|
||||
g_main_context_wakeup(g_source_get_context((GSource *)data));
|
||||
}
|
||||
|
||||
static void
|
||||
redis_source_cleanup (gpointer data)
|
||||
{
|
||||
RedisSource *source = (RedisSource *)data;
|
||||
|
||||
g_return_if_fail(source);
|
||||
|
||||
redis_source_del_read(source);
|
||||
redis_source_del_write(source);
|
||||
/*
|
||||
* It is not our responsibility to remove ourself from the
|
||||
* current main loop. However, we will remove the GPollFD.
|
||||
*/
|
||||
if (source->poll_fd.fd >= 0) {
|
||||
g_source_remove_poll((GSource *)data, &source->poll_fd);
|
||||
source->poll_fd.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
redis_source_prepare (GSource *source,
|
||||
gint *timeout_)
|
||||
{
|
||||
RedisSource *redis = (RedisSource *)source;
|
||||
*timeout_ = -1;
|
||||
return !!(redis->poll_fd.events & redis->poll_fd.revents);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
redis_source_check (GSource *source)
|
||||
{
|
||||
RedisSource *redis = (RedisSource *)source;
|
||||
return !!(redis->poll_fd.events & redis->poll_fd.revents);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
redis_source_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
RedisSource *redis = (RedisSource *)source;
|
||||
|
||||
if ((redis->poll_fd.revents & G_IO_OUT)) {
|
||||
redisAsyncHandleWrite(redis->ac);
|
||||
redis->poll_fd.revents &= ~G_IO_OUT;
|
||||
}
|
||||
|
||||
if ((redis->poll_fd.revents & G_IO_IN)) {
|
||||
redisAsyncHandleRead(redis->ac);
|
||||
redis->poll_fd.revents &= ~G_IO_IN;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
return callback(user_data);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
redis_source_finalize (GSource *source)
|
||||
{
|
||||
RedisSource *redis = (RedisSource *)source;
|
||||
|
||||
if (redis->poll_fd.fd >= 0) {
|
||||
g_source_remove_poll(source, &redis->poll_fd);
|
||||
redis->poll_fd.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static GSource *
|
||||
redis_source_new (redisAsyncContext *ac)
|
||||
{
|
||||
static GSourceFuncs source_funcs = {
|
||||
.prepare = redis_source_prepare,
|
||||
.check = redis_source_check,
|
||||
.dispatch = redis_source_dispatch,
|
||||
.finalize = redis_source_finalize,
|
||||
};
|
||||
redisContext *c = &ac->c;
|
||||
RedisSource *source;
|
||||
|
||||
g_return_val_if_fail(ac != NULL, NULL);
|
||||
|
||||
source = (RedisSource *)g_source_new(&source_funcs, sizeof *source);
|
||||
if (source == NULL)
|
||||
return NULL;
|
||||
|
||||
source->ac = ac;
|
||||
source->poll_fd.fd = c->fd;
|
||||
source->poll_fd.events = 0;
|
||||
source->poll_fd.revents = 0;
|
||||
g_source_add_poll((GSource *)source, &source->poll_fd);
|
||||
|
||||
ac->ev.addRead = redis_source_add_read;
|
||||
ac->ev.delRead = redis_source_del_read;
|
||||
ac->ev.addWrite = redis_source_add_write;
|
||||
ac->ev.delWrite = redis_source_del_write;
|
||||
ac->ev.cleanup = redis_source_cleanup;
|
||||
ac->ev.data = source;
|
||||
|
||||
return (GSource *)source;
|
||||
}
|
||||
|
||||
#endif /* __HIREDIS_GLIB_H__ */
|
84
ext/hiredis-1.0.2/adapters/ivykis.h
Normal file
84
ext/hiredis-1.0.2/adapters/ivykis.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef __HIREDIS_IVYKIS_H__
|
||||
#define __HIREDIS_IVYKIS_H__
|
||||
#include <iv.h>
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
typedef struct redisIvykisEvents {
|
||||
redisAsyncContext *context;
|
||||
struct iv_fd fd;
|
||||
} redisIvykisEvents;
|
||||
|
||||
static void redisIvykisReadEvent(void *arg) {
|
||||
redisAsyncContext *context = (redisAsyncContext *)arg;
|
||||
redisAsyncHandleRead(context);
|
||||
}
|
||||
|
||||
static void redisIvykisWriteEvent(void *arg) {
|
||||
redisAsyncContext *context = (redisAsyncContext *)arg;
|
||||
redisAsyncHandleWrite(context);
|
||||
}
|
||||
|
||||
static void redisIvykisAddRead(void *privdata) {
|
||||
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
|
||||
iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent);
|
||||
}
|
||||
|
||||
static void redisIvykisDelRead(void *privdata) {
|
||||
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
|
||||
iv_fd_set_handler_in(&e->fd, NULL);
|
||||
}
|
||||
|
||||
static void redisIvykisAddWrite(void *privdata) {
|
||||
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
|
||||
iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent);
|
||||
}
|
||||
|
||||
static void redisIvykisDelWrite(void *privdata) {
|
||||
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
|
||||
iv_fd_set_handler_out(&e->fd, NULL);
|
||||
}
|
||||
|
||||
static void redisIvykisCleanup(void *privdata) {
|
||||
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
|
||||
|
||||
iv_fd_unregister(&e->fd);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static int redisIvykisAttach(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisIvykisEvents *e;
|
||||
|
||||
/* Nothing should be attached when something is already attached */
|
||||
if (ac->ev.data != NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisIvykisEvents*)hi_malloc(sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
ac->ev.addRead = redisIvykisAddRead;
|
||||
ac->ev.delRead = redisIvykisDelRead;
|
||||
ac->ev.addWrite = redisIvykisAddWrite;
|
||||
ac->ev.delWrite = redisIvykisDelWrite;
|
||||
ac->ev.cleanup = redisIvykisCleanup;
|
||||
ac->ev.data = e;
|
||||
|
||||
/* Initialize and install read/write events */
|
||||
IV_FD_INIT(&e->fd);
|
||||
e->fd.fd = c->fd;
|
||||
e->fd.handler_in = redisIvykisReadEvent;
|
||||
e->fd.handler_out = redisIvykisWriteEvent;
|
||||
e->fd.handler_err = NULL;
|
||||
e->fd.cookie = e->context;
|
||||
|
||||
iv_fd_register(&e->fd);
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif
|
179
ext/hiredis-1.0.2/adapters/libev.h
Normal file
179
ext/hiredis-1.0.2/adapters/libev.h
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_LIBEV_H__
|
||||
#define __HIREDIS_LIBEV_H__
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <ev.h>
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
typedef struct redisLibevEvents {
|
||||
redisAsyncContext *context;
|
||||
struct ev_loop *loop;
|
||||
int reading, writing;
|
||||
ev_io rev, wev;
|
||||
ev_timer timer;
|
||||
} redisLibevEvents;
|
||||
|
||||
static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
|
||||
#if EV_MULTIPLICITY
|
||||
((void)loop);
|
||||
#endif
|
||||
((void)revents);
|
||||
|
||||
redisLibevEvents *e = (redisLibevEvents*)watcher->data;
|
||||
redisAsyncHandleRead(e->context);
|
||||
}
|
||||
|
||||
static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
|
||||
#if EV_MULTIPLICITY
|
||||
((void)loop);
|
||||
#endif
|
||||
((void)revents);
|
||||
|
||||
redisLibevEvents *e = (redisLibevEvents*)watcher->data;
|
||||
redisAsyncHandleWrite(e->context);
|
||||
}
|
||||
|
||||
static void redisLibevAddRead(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
if (!e->reading) {
|
||||
e->reading = 1;
|
||||
ev_io_start(EV_A_ &e->rev);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibevDelRead(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
if (e->reading) {
|
||||
e->reading = 0;
|
||||
ev_io_stop(EV_A_ &e->rev);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibevAddWrite(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
if (!e->writing) {
|
||||
e->writing = 1;
|
||||
ev_io_start(EV_A_ &e->wev);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibevDelWrite(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
if (e->writing) {
|
||||
e->writing = 0;
|
||||
ev_io_stop(EV_A_ &e->wev);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibevStopTimer(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
ev_timer_stop(EV_A_ &e->timer);
|
||||
}
|
||||
|
||||
static void redisLibevCleanup(void *privdata) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
redisLibevDelRead(privdata);
|
||||
redisLibevDelWrite(privdata);
|
||||
redisLibevStopTimer(privdata);
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) {
|
||||
((void)revents);
|
||||
redisLibevEvents *e = (redisLibevEvents*)timer->data;
|
||||
redisAsyncHandleTimeout(e->context);
|
||||
}
|
||||
|
||||
static void redisLibevSetTimeout(void *privdata, struct timeval tv) {
|
||||
redisLibevEvents *e = (redisLibevEvents*)privdata;
|
||||
struct ev_loop *loop = e->loop;
|
||||
((void)loop);
|
||||
|
||||
if (!ev_is_active(&e->timer)) {
|
||||
ev_init(&e->timer, redisLibevTimeout);
|
||||
e->timer.data = e;
|
||||
}
|
||||
|
||||
e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00;
|
||||
ev_timer_again(EV_A_ &e->timer);
|
||||
}
|
||||
|
||||
static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisLibevEvents *e;
|
||||
|
||||
/* Nothing should be attached when something is already attached */
|
||||
if (ac->ev.data != NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisLibevEvents*)hi_calloc(1, sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
#if EV_MULTIPLICITY
|
||||
e->loop = loop;
|
||||
#else
|
||||
e->loop = NULL;
|
||||
#endif
|
||||
e->rev.data = e;
|
||||
e->wev.data = e;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
ac->ev.addRead = redisLibevAddRead;
|
||||
ac->ev.delRead = redisLibevDelRead;
|
||||
ac->ev.addWrite = redisLibevAddWrite;
|
||||
ac->ev.delWrite = redisLibevDelWrite;
|
||||
ac->ev.cleanup = redisLibevCleanup;
|
||||
ac->ev.scheduleTimer = redisLibevSetTimeout;
|
||||
ac->ev.data = e;
|
||||
|
||||
/* Initialize read/write events */
|
||||
ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ);
|
||||
ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE);
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
#endif
|
175
ext/hiredis-1.0.2/adapters/libevent.h
Normal file
175
ext/hiredis-1.0.2/adapters/libevent.h
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_LIBEVENT_H__
|
||||
#define __HIREDIS_LIBEVENT_H__
|
||||
#include <event2/event.h>
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
#define REDIS_LIBEVENT_DELETED 0x01
|
||||
#define REDIS_LIBEVENT_ENTERED 0x02
|
||||
|
||||
typedef struct redisLibeventEvents {
|
||||
redisAsyncContext *context;
|
||||
struct event *ev;
|
||||
struct event_base *base;
|
||||
struct timeval tv;
|
||||
short flags;
|
||||
short state;
|
||||
} redisLibeventEvents;
|
||||
|
||||
static void redisLibeventDestroy(redisLibeventEvents *e) {
|
||||
hi_free(e);
|
||||
}
|
||||
|
||||
static void redisLibeventHandler(int fd, short event, void *arg) {
|
||||
((void)fd);
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)arg;
|
||||
e->state |= REDIS_LIBEVENT_ENTERED;
|
||||
|
||||
#define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\
|
||||
redisLibeventDestroy(e);\
|
||||
return; \
|
||||
}
|
||||
|
||||
if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
|
||||
redisAsyncHandleTimeout(e->context);
|
||||
CHECK_DELETED();
|
||||
}
|
||||
|
||||
if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
|
||||
redisAsyncHandleRead(e->context);
|
||||
CHECK_DELETED();
|
||||
}
|
||||
|
||||
if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
|
||||
redisAsyncHandleWrite(e->context);
|
||||
CHECK_DELETED();
|
||||
}
|
||||
|
||||
e->state &= ~REDIS_LIBEVENT_ENTERED;
|
||||
#undef CHECK_DELETED
|
||||
}
|
||||
|
||||
static void redisLibeventUpdate(void *privdata, short flag, int isRemove) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
|
||||
const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL;
|
||||
|
||||
if (isRemove) {
|
||||
if ((e->flags & flag) == 0) {
|
||||
return;
|
||||
} else {
|
||||
e->flags &= ~flag;
|
||||
}
|
||||
} else {
|
||||
if (e->flags & flag) {
|
||||
return;
|
||||
} else {
|
||||
e->flags |= flag;
|
||||
}
|
||||
}
|
||||
|
||||
event_del(e->ev);
|
||||
event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST,
|
||||
redisLibeventHandler, privdata);
|
||||
event_add(e->ev, tv);
|
||||
}
|
||||
|
||||
static void redisLibeventAddRead(void *privdata) {
|
||||
redisLibeventUpdate(privdata, EV_READ, 0);
|
||||
}
|
||||
|
||||
static void redisLibeventDelRead(void *privdata) {
|
||||
redisLibeventUpdate(privdata, EV_READ, 1);
|
||||
}
|
||||
|
||||
static void redisLibeventAddWrite(void *privdata) {
|
||||
redisLibeventUpdate(privdata, EV_WRITE, 0);
|
||||
}
|
||||
|
||||
static void redisLibeventDelWrite(void *privdata) {
|
||||
redisLibeventUpdate(privdata, EV_WRITE, 1);
|
||||
}
|
||||
|
||||
static void redisLibeventCleanup(void *privdata) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
event_del(e->ev);
|
||||
event_free(e->ev);
|
||||
e->ev = NULL;
|
||||
|
||||
if (e->state & REDIS_LIBEVENT_ENTERED) {
|
||||
e->state |= REDIS_LIBEVENT_DELETED;
|
||||
} else {
|
||||
redisLibeventDestroy(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisLibeventSetTimeout(void *privdata, struct timeval tv) {
|
||||
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
|
||||
short flags = e->flags;
|
||||
e->flags = 0;
|
||||
e->tv = tv;
|
||||
redisLibeventUpdate(e, flags, 0);
|
||||
}
|
||||
|
||||
static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisLibeventEvents *e;
|
||||
|
||||
/* Nothing should be attached when something is already attached */
|
||||
if (ac->ev.data != NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Create container for context and r/w events */
|
||||
e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e));
|
||||
if (e == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
e->context = ac;
|
||||
|
||||
/* Register functions to start/stop listening for events */
|
||||
ac->ev.addRead = redisLibeventAddRead;
|
||||
ac->ev.delRead = redisLibeventDelRead;
|
||||
ac->ev.addWrite = redisLibeventAddWrite;
|
||||
ac->ev.delWrite = redisLibeventDelWrite;
|
||||
ac->ev.cleanup = redisLibeventCleanup;
|
||||
ac->ev.scheduleTimer = redisLibeventSetTimeout;
|
||||
ac->ev.data = e;
|
||||
|
||||
/* Initialize and install read/write events */
|
||||
e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e);
|
||||
e->base = base;
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif
|
117
ext/hiredis-1.0.2/adapters/libuv.h
Normal file
117
ext/hiredis-1.0.2/adapters/libuv.h
Normal file
@ -0,0 +1,117 @@
|
||||
#ifndef __HIREDIS_LIBUV_H__
|
||||
#define __HIREDIS_LIBUV_H__
|
||||
#include <stdlib.h>
|
||||
#include <uv.h>
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
#include <string.h>
|
||||
|
||||
typedef struct redisLibuvEvents {
|
||||
redisAsyncContext* context;
|
||||
uv_poll_t handle;
|
||||
int events;
|
||||
} redisLibuvEvents;
|
||||
|
||||
|
||||
static void redisLibuvPoll(uv_poll_t* handle, int status, int events) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
|
||||
int ev = (status ? p->events : events);
|
||||
|
||||
if (p->context != NULL && (ev & UV_READABLE)) {
|
||||
redisAsyncHandleRead(p->context);
|
||||
}
|
||||
if (p->context != NULL && (ev & UV_WRITABLE)) {
|
||||
redisAsyncHandleWrite(p->context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void redisLibuvAddRead(void *privdata) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
|
||||
|
||||
p->events |= UV_READABLE;
|
||||
|
||||
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
|
||||
}
|
||||
|
||||
|
||||
static void redisLibuvDelRead(void *privdata) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
|
||||
|
||||
p->events &= ~UV_READABLE;
|
||||
|
||||
if (p->events) {
|
||||
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
|
||||
} else {
|
||||
uv_poll_stop(&p->handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void redisLibuvAddWrite(void *privdata) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
|
||||
|
||||
p->events |= UV_WRITABLE;
|
||||
|
||||
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
|
||||
}
|
||||
|
||||
|
||||
static void redisLibuvDelWrite(void *privdata) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
|
||||
|
||||
p->events &= ~UV_WRITABLE;
|
||||
|
||||
if (p->events) {
|
||||
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
|
||||
} else {
|
||||
uv_poll_stop(&p->handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_close(uv_handle_t* handle) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
|
||||
|
||||
hi_free(p);
|
||||
}
|
||||
|
||||
|
||||
static void redisLibuvCleanup(void *privdata) {
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
|
||||
|
||||
p->context = NULL; // indicate that context might no longer exist
|
||||
uv_close((uv_handle_t*)&p->handle, on_close);
|
||||
}
|
||||
|
||||
|
||||
static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (ac->ev.data != NULL) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
ac->ev.addRead = redisLibuvAddRead;
|
||||
ac->ev.delRead = redisLibuvDelRead;
|
||||
ac->ev.addWrite = redisLibuvAddWrite;
|
||||
ac->ev.delWrite = redisLibuvDelWrite;
|
||||
ac->ev.cleanup = redisLibuvCleanup;
|
||||
|
||||
redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p));
|
||||
if (p == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
if (uv_poll_init_socket(loop, &p->handle, c->fd) != 0) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
ac->ev.data = p;
|
||||
p->handle.data = p;
|
||||
p->context = ac;
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif
|
115
ext/hiredis-1.0.2/adapters/macosx.h
Normal file
115
ext/hiredis-1.0.2/adapters/macosx.h
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// Created by Дмитрий Бахвалов on 13.07.15.
|
||||
// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __HIREDIS_MACOSX_H__
|
||||
#define __HIREDIS_MACOSX_H__
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include "../hiredis.h"
|
||||
#include "../async.h"
|
||||
|
||||
typedef struct {
|
||||
redisAsyncContext *context;
|
||||
CFSocketRef socketRef;
|
||||
CFRunLoopSourceRef sourceRef;
|
||||
} RedisRunLoop;
|
||||
|
||||
static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) {
|
||||
if( redisRunLoop != NULL ) {
|
||||
if( redisRunLoop->sourceRef != NULL ) {
|
||||
CFRunLoopSourceInvalidate(redisRunLoop->sourceRef);
|
||||
CFRelease(redisRunLoop->sourceRef);
|
||||
}
|
||||
if( redisRunLoop->socketRef != NULL ) {
|
||||
CFSocketInvalidate(redisRunLoop->socketRef);
|
||||
CFRelease(redisRunLoop->socketRef);
|
||||
}
|
||||
hi_free(redisRunLoop);
|
||||
}
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static void redisMacOSAddRead(void *privdata) {
|
||||
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
|
||||
CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack);
|
||||
}
|
||||
|
||||
static void redisMacOSDelRead(void *privdata) {
|
||||
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
|
||||
CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack);
|
||||
}
|
||||
|
||||
static void redisMacOSAddWrite(void *privdata) {
|
||||
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
|
||||
CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack);
|
||||
}
|
||||
|
||||
static void redisMacOSDelWrite(void *privdata) {
|
||||
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
|
||||
CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack);
|
||||
}
|
||||
|
||||
static void redisMacOSCleanup(void *privdata) {
|
||||
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
|
||||
freeRedisRunLoop(redisRunLoop);
|
||||
}
|
||||
|
||||
static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) {
|
||||
redisAsyncContext* context = (redisAsyncContext*) info;
|
||||
|
||||
switch (callbackType) {
|
||||
case kCFSocketReadCallBack:
|
||||
redisAsyncHandleRead(context);
|
||||
break;
|
||||
|
||||
case kCFSocketWriteCallBack:
|
||||
redisAsyncHandleWrite(context);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) {
|
||||
redisContext *redisCtx = &(redisAsyncCtx->c);
|
||||
|
||||
/* Nothing should be attached when something is already attached */
|
||||
if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR;
|
||||
|
||||
RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop));
|
||||
if (redisRunLoop == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Setup redis stuff */
|
||||
redisRunLoop->context = redisAsyncCtx;
|
||||
|
||||
redisAsyncCtx->ev.addRead = redisMacOSAddRead;
|
||||
redisAsyncCtx->ev.delRead = redisMacOSDelRead;
|
||||
redisAsyncCtx->ev.addWrite = redisMacOSAddWrite;
|
||||
redisAsyncCtx->ev.delWrite = redisMacOSDelWrite;
|
||||
redisAsyncCtx->ev.cleanup = redisMacOSCleanup;
|
||||
redisAsyncCtx->ev.data = redisRunLoop;
|
||||
|
||||
/* Initialize and install read/write events */
|
||||
CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL };
|
||||
|
||||
redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd,
|
||||
kCFSocketReadCallBack | kCFSocketWriteCallBack,
|
||||
redisMacOSAsyncCallback,
|
||||
&socketCtx);
|
||||
if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop);
|
||||
|
||||
redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0);
|
||||
if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop);
|
||||
|
||||
CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode);
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
135
ext/hiredis-1.0.2/adapters/qt.h
Normal file
135
ext/hiredis-1.0.2/adapters/qt.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*-
|
||||
* Copyright (C) 2014 Pietro Cerutti <gahr@gahr.ch>
|
||||
*
|
||||
* 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 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
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR 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.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_QT_H__
|
||||
#define __HIREDIS_QT_H__
|
||||
#include <QSocketNotifier>
|
||||
#include "../async.h"
|
||||
|
||||
static void RedisQtAddRead(void *);
|
||||
static void RedisQtDelRead(void *);
|
||||
static void RedisQtAddWrite(void *);
|
||||
static void RedisQtDelWrite(void *);
|
||||
static void RedisQtCleanup(void *);
|
||||
|
||||
class RedisQtAdapter : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
friend
|
||||
void RedisQtAddRead(void * adapter) {
|
||||
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
|
||||
a->addRead();
|
||||
}
|
||||
|
||||
friend
|
||||
void RedisQtDelRead(void * adapter) {
|
||||
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
|
||||
a->delRead();
|
||||
}
|
||||
|
||||
friend
|
||||
void RedisQtAddWrite(void * adapter) {
|
||||
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
|
||||
a->addWrite();
|
||||
}
|
||||
|
||||
friend
|
||||
void RedisQtDelWrite(void * adapter) {
|
||||
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
|
||||
a->delWrite();
|
||||
}
|
||||
|
||||
friend
|
||||
void RedisQtCleanup(void * adapter) {
|
||||
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
|
||||
a->cleanup();
|
||||
}
|
||||
|
||||
public:
|
||||
RedisQtAdapter(QObject * parent = 0)
|
||||
: QObject(parent), m_ctx(0), m_read(0), m_write(0) { }
|
||||
|
||||
~RedisQtAdapter() {
|
||||
if (m_ctx != 0) {
|
||||
m_ctx->ev.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int setContext(redisAsyncContext * ac) {
|
||||
if (ac->ev.data != NULL) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
m_ctx = ac;
|
||||
m_ctx->ev.data = this;
|
||||
m_ctx->ev.addRead = RedisQtAddRead;
|
||||
m_ctx->ev.delRead = RedisQtDelRead;
|
||||
m_ctx->ev.addWrite = RedisQtAddWrite;
|
||||
m_ctx->ev.delWrite = RedisQtDelWrite;
|
||||
m_ctx->ev.cleanup = RedisQtCleanup;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
void addRead() {
|
||||
if (m_read) return;
|
||||
m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0);
|
||||
connect(m_read, SIGNAL(activated(int)), this, SLOT(read()));
|
||||
}
|
||||
|
||||
void delRead() {
|
||||
if (!m_read) return;
|
||||
delete m_read;
|
||||
m_read = 0;
|
||||
}
|
||||
|
||||
void addWrite() {
|
||||
if (m_write) return;
|
||||
m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0);
|
||||
connect(m_write, SIGNAL(activated(int)), this, SLOT(write()));
|
||||
}
|
||||
|
||||
void delWrite() {
|
||||
if (!m_write) return;
|
||||
delete m_write;
|
||||
m_write = 0;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
delRead();
|
||||
delWrite();
|
||||
}
|
||||
|
||||
private slots:
|
||||
void read() { redisAsyncHandleRead(m_ctx); }
|
||||
void write() { redisAsyncHandleWrite(m_ctx); }
|
||||
|
||||
private:
|
||||
redisAsyncContext * m_ctx;
|
||||
QSocketNotifier * m_read;
|
||||
QSocketNotifier * m_write;
|
||||
};
|
||||
|
||||
#endif /* !__HIREDIS_QT_H__ */
|
86
ext/hiredis-1.0.2/alloc.c
Normal file
86
ext/hiredis-1.0.2/alloc.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "alloc.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
hiredisAllocFuncs hiredisAllocFns = {
|
||||
.mallocFn = malloc,
|
||||
.callocFn = calloc,
|
||||
.reallocFn = realloc,
|
||||
.strdupFn = strdup,
|
||||
.freeFn = free,
|
||||
};
|
||||
|
||||
/* Override hiredis' allocators with ones supplied by the user */
|
||||
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *override) {
|
||||
hiredisAllocFuncs orig = hiredisAllocFns;
|
||||
|
||||
hiredisAllocFns = *override;
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
/* Reset allocators to use libc defaults */
|
||||
void hiredisResetAllocators(void) {
|
||||
hiredisAllocFns = (hiredisAllocFuncs) {
|
||||
.mallocFn = malloc,
|
||||
.callocFn = calloc,
|
||||
.reallocFn = realloc,
|
||||
.strdupFn = strdup,
|
||||
.freeFn = free,
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void *hi_malloc(size_t size) {
|
||||
return hiredisAllocFns.mallocFn(size);
|
||||
}
|
||||
|
||||
void *hi_calloc(size_t nmemb, size_t size) {
|
||||
return hiredisAllocFns.callocFn(nmemb, size);
|
||||
}
|
||||
|
||||
void *hi_realloc(void *ptr, size_t size) {
|
||||
return hiredisAllocFns.reallocFn(ptr, size);
|
||||
}
|
||||
|
||||
char *hi_strdup(const char *str) {
|
||||
return hiredisAllocFns.strdupFn(str);
|
||||
}
|
||||
|
||||
void hi_free(void *ptr) {
|
||||
hiredisAllocFns.freeFn(ptr);
|
||||
}
|
||||
|
||||
#endif
|
91
ext/hiredis-1.0.2/alloc.h
Normal file
91
ext/hiredis-1.0.2/alloc.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef HIREDIS_ALLOC_H
|
||||
#define HIREDIS_ALLOC_H
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structure pointing to our actually configured allocators */
|
||||
typedef struct hiredisAllocFuncs {
|
||||
void *(*mallocFn)(size_t);
|
||||
void *(*callocFn)(size_t,size_t);
|
||||
void *(*reallocFn)(void*,size_t);
|
||||
char *(*strdupFn)(const char*);
|
||||
void (*freeFn)(void*);
|
||||
} hiredisAllocFuncs;
|
||||
|
||||
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha);
|
||||
void hiredisResetAllocators(void);
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/* Hiredis' configured allocator function pointer struct */
|
||||
extern hiredisAllocFuncs hiredisAllocFns;
|
||||
|
||||
static inline void *hi_malloc(size_t size) {
|
||||
return hiredisAllocFns.mallocFn(size);
|
||||
}
|
||||
|
||||
static inline void *hi_calloc(size_t nmemb, size_t size) {
|
||||
return hiredisAllocFns.callocFn(nmemb, size);
|
||||
}
|
||||
|
||||
static inline void *hi_realloc(void *ptr, size_t size) {
|
||||
return hiredisAllocFns.reallocFn(ptr, size);
|
||||
}
|
||||
|
||||
static inline char *hi_strdup(const char *str) {
|
||||
return hiredisAllocFns.strdupFn(str);
|
||||
}
|
||||
|
||||
static inline void hi_free(void *ptr) {
|
||||
hiredisAllocFns.freeFn(ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *hi_malloc(size_t size);
|
||||
void *hi_calloc(size_t nmemb, size_t size);
|
||||
void *hi_realloc(void *ptr, size_t size);
|
||||
char *hi_strdup(const char *str);
|
||||
void hi_free(void *ptr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HIREDIS_ALLOC_H */
|
24
ext/hiredis-1.0.2/appveyor.yml
Normal file
24
ext/hiredis-1.0.2/appveyor.yml
Normal file
@ -0,0 +1,24 @@
|
||||
# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin)
|
||||
environment:
|
||||
matrix:
|
||||
- CYG_BASH: C:\cygwin64\bin\bash
|
||||
CC: gcc
|
||||
- CYG_BASH: C:\cygwin\bin\bash
|
||||
CC: gcc
|
||||
CFLAGS: -m32
|
||||
CXXFLAGS: -m32
|
||||
LDFLAGS: -m32
|
||||
|
||||
clone_depth: 1
|
||||
|
||||
# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
# Install needed build dependencies
|
||||
install:
|
||||
- '%CYG_BASH% -lc "cygcheck -dc cygwin"'
|
||||
|
||||
build_script:
|
||||
- 'echo building...'
|
||||
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; mkdir build && cd build && cmake .. -G \"Unix Makefiles\" && make VERBOSE=1"'
|
887
ext/hiredis-1.0.2/async.c
Normal file
887
ext/hiredis-1.0.2/async.c
Normal file
@ -0,0 +1,887 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include "async.h"
|
||||
#include "net.h"
|
||||
#include "dict.c"
|
||||
#include "sds.h"
|
||||
#include "win32.h"
|
||||
|
||||
#include "async_private.h"
|
||||
|
||||
/* Forward declarations of hiredis.c functions */
|
||||
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len);
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
/* Functions managing dictionary of callbacks for pub/sub. */
|
||||
static unsigned int callbackHash(const void *key) {
|
||||
return dictGenHashFunction((const unsigned char *)key,
|
||||
sdslen((const sds)key));
|
||||
}
|
||||
|
||||
static void *callbackValDup(void *privdata, const void *src) {
|
||||
((void) privdata);
|
||||
redisCallback *dup;
|
||||
|
||||
dup = hi_malloc(sizeof(*dup));
|
||||
if (dup == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(dup,src,sizeof(*dup));
|
||||
return dup;
|
||||
}
|
||||
|
||||
static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) {
|
||||
int l1, l2;
|
||||
((void) privdata);
|
||||
|
||||
l1 = sdslen((const sds)key1);
|
||||
l2 = sdslen((const sds)key2);
|
||||
if (l1 != l2) return 0;
|
||||
return memcmp(key1,key2,l1) == 0;
|
||||
}
|
||||
|
||||
static void callbackKeyDestructor(void *privdata, void *key) {
|
||||
((void) privdata);
|
||||
sdsfree((sds)key);
|
||||
}
|
||||
|
||||
static void callbackValDestructor(void *privdata, void *val) {
|
||||
((void) privdata);
|
||||
hi_free(val);
|
||||
}
|
||||
|
||||
static dictType callbackDict = {
|
||||
callbackHash,
|
||||
NULL,
|
||||
callbackValDup,
|
||||
callbackKeyCompare,
|
||||
callbackKeyDestructor,
|
||||
callbackValDestructor
|
||||
};
|
||||
|
||||
static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
|
||||
redisAsyncContext *ac;
|
||||
dict *channels = NULL, *patterns = NULL;
|
||||
|
||||
channels = dictCreate(&callbackDict,NULL);
|
||||
if (channels == NULL)
|
||||
goto oom;
|
||||
|
||||
patterns = dictCreate(&callbackDict,NULL);
|
||||
if (patterns == NULL)
|
||||
goto oom;
|
||||
|
||||
ac = hi_realloc(c,sizeof(redisAsyncContext));
|
||||
if (ac == NULL)
|
||||
goto oom;
|
||||
|
||||
c = &(ac->c);
|
||||
|
||||
/* The regular connect functions will always set the flag REDIS_CONNECTED.
|
||||
* For the async API, we want to wait until the first write event is
|
||||
* received up before setting this flag, so reset it here. */
|
||||
c->flags &= ~REDIS_CONNECTED;
|
||||
|
||||
ac->err = 0;
|
||||
ac->errstr = NULL;
|
||||
ac->data = NULL;
|
||||
ac->dataCleanup = NULL;
|
||||
|
||||
ac->ev.data = NULL;
|
||||
ac->ev.addRead = NULL;
|
||||
ac->ev.delRead = NULL;
|
||||
ac->ev.addWrite = NULL;
|
||||
ac->ev.delWrite = NULL;
|
||||
ac->ev.cleanup = NULL;
|
||||
ac->ev.scheduleTimer = NULL;
|
||||
|
||||
ac->onConnect = NULL;
|
||||
ac->onDisconnect = NULL;
|
||||
|
||||
ac->replies.head = NULL;
|
||||
ac->replies.tail = NULL;
|
||||
ac->sub.invalid.head = NULL;
|
||||
ac->sub.invalid.tail = NULL;
|
||||
ac->sub.channels = channels;
|
||||
ac->sub.patterns = patterns;
|
||||
|
||||
return ac;
|
||||
oom:
|
||||
if (channels) dictRelease(channels);
|
||||
if (patterns) dictRelease(patterns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We want the error field to be accessible directly instead of requiring
|
||||
* an indirection to the redisContext struct. */
|
||||
static void __redisAsyncCopyError(redisAsyncContext *ac) {
|
||||
if (!ac)
|
||||
return;
|
||||
|
||||
redisContext *c = &(ac->c);
|
||||
ac->err = c->err;
|
||||
ac->errstr = c->errstr;
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) {
|
||||
redisOptions myOptions = *options;
|
||||
redisContext *c;
|
||||
redisAsyncContext *ac;
|
||||
|
||||
/* Clear any erroneously set sync callback and flag that we don't want to
|
||||
* use freeReplyObject by default. */
|
||||
myOptions.push_cb = NULL;
|
||||
myOptions.options |= REDIS_OPT_NO_PUSH_AUTOFREE;
|
||||
|
||||
myOptions.options |= REDIS_OPT_NONBLOCK;
|
||||
c = redisConnectWithOptions(&myOptions);
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ac = redisAsyncInitialize(c);
|
||||
if (ac == NULL) {
|
||||
redisFree(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set any configured async push handler */
|
||||
redisAsyncSetPushCallback(ac, myOptions.async_push_cb);
|
||||
|
||||
__redisAsyncCopyError(ac);
|
||||
return ac;
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
|
||||
const char *source_addr) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.endpoint.tcp.source_addr = source_addr;
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
||||
const char *source_addr) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, ip, port);
|
||||
options.options |= REDIS_OPT_REUSEADDR;
|
||||
options.endpoint.tcp.source_addr = source_addr;
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
redisAsyncContext *redisAsyncConnectUnix(const char *path) {
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_UNIX(&options, path);
|
||||
return redisAsyncConnectWithOptions(&options);
|
||||
}
|
||||
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
|
||||
if (ac->onConnect == NULL) {
|
||||
ac->onConnect = fn;
|
||||
|
||||
/* The common way to detect an established connection is to wait for
|
||||
* the first write event to be fired. This assumes the related event
|
||||
* library functions are already set. */
|
||||
_EL_ADD_WRITE(ac);
|
||||
return REDIS_OK;
|
||||
}
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) {
|
||||
if (ac->onDisconnect == NULL) {
|
||||
ac->onDisconnect = fn;
|
||||
return REDIS_OK;
|
||||
}
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Helper functions to push/shift callbacks */
|
||||
static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
|
||||
redisCallback *cb;
|
||||
|
||||
/* Copy callback from stack to heap */
|
||||
cb = hi_malloc(sizeof(*cb));
|
||||
if (cb == NULL)
|
||||
return REDIS_ERR_OOM;
|
||||
|
||||
if (source != NULL) {
|
||||
memcpy(cb,source,sizeof(*cb));
|
||||
cb->next = NULL;
|
||||
}
|
||||
|
||||
/* Store callback in list */
|
||||
if (list->head == NULL)
|
||||
list->head = cb;
|
||||
if (list->tail != NULL)
|
||||
list->tail->next = cb;
|
||||
list->tail = cb;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) {
|
||||
redisCallback *cb = list->head;
|
||||
if (cb != NULL) {
|
||||
list->head = cb->next;
|
||||
if (cb == list->tail)
|
||||
list->tail = NULL;
|
||||
|
||||
/* Copy callback from heap to stack */
|
||||
if (target != NULL)
|
||||
memcpy(target,cb,sizeof(*cb));
|
||||
hi_free(cb);
|
||||
return REDIS_OK;
|
||||
}
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) {
|
||||
redisContext *c = &(ac->c);
|
||||
if (cb->fn != NULL) {
|
||||
c->flags |= REDIS_IN_CALLBACK;
|
||||
cb->fn(ac,reply,cb->privdata);
|
||||
c->flags &= ~REDIS_IN_CALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) {
|
||||
if (ac->push_cb != NULL) {
|
||||
ac->c.flags |= REDIS_IN_CALLBACK;
|
||||
ac->push_cb(ac, reply);
|
||||
ac->c.flags &= ~REDIS_IN_CALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function to free the context. */
|
||||
static void __redisAsyncFree(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb;
|
||||
dictIterator *it;
|
||||
dictEntry *de;
|
||||
|
||||
/* Execute pending callbacks with NULL reply. */
|
||||
while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK)
|
||||
__redisRunCallback(ac,&cb,NULL);
|
||||
|
||||
/* Execute callbacks for invalid commands */
|
||||
while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
|
||||
__redisRunCallback(ac,&cb,NULL);
|
||||
|
||||
/* Run subscription callbacks with NULL reply */
|
||||
if (ac->sub.channels) {
|
||||
it = dictGetIterator(ac->sub.channels);
|
||||
if (it != NULL) {
|
||||
while ((de = dictNext(it)) != NULL)
|
||||
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
|
||||
dictReleaseIterator(it);
|
||||
}
|
||||
|
||||
dictRelease(ac->sub.channels);
|
||||
}
|
||||
|
||||
if (ac->sub.patterns) {
|
||||
it = dictGetIterator(ac->sub.patterns);
|
||||
if (it != NULL) {
|
||||
while ((de = dictNext(it)) != NULL)
|
||||
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
|
||||
dictReleaseIterator(it);
|
||||
}
|
||||
|
||||
dictRelease(ac->sub.patterns);
|
||||
}
|
||||
|
||||
/* Signal event lib to clean up */
|
||||
_EL_CLEANUP(ac);
|
||||
|
||||
/* Execute disconnect callback. When redisAsyncFree() initiated destroying
|
||||
* this context, the status will always be REDIS_OK. */
|
||||
if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
|
||||
if (c->flags & REDIS_FREEING) {
|
||||
ac->onDisconnect(ac,REDIS_OK);
|
||||
} else {
|
||||
ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
if (ac->dataCleanup) {
|
||||
ac->dataCleanup(ac->data);
|
||||
}
|
||||
|
||||
/* Cleanup self */
|
||||
redisFree(c);
|
||||
}
|
||||
|
||||
/* Free the async context. When this function is called from a callback,
|
||||
* control needs to be returned to redisProcessCallbacks() before actual
|
||||
* free'ing. To do so, a flag is set on the context which is picked up by
|
||||
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
|
||||
void redisAsyncFree(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
c->flags |= REDIS_FREEING;
|
||||
if (!(c->flags & REDIS_IN_CALLBACK))
|
||||
__redisAsyncFree(ac);
|
||||
}
|
||||
|
||||
/* Helper function to make the disconnect happen and clean up. */
|
||||
void __redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
/* Make sure error is accessible if there is any */
|
||||
__redisAsyncCopyError(ac);
|
||||
|
||||
if (ac->err == 0) {
|
||||
/* For clean disconnects, there should be no pending callbacks. */
|
||||
int ret = __redisShiftCallback(&ac->replies,NULL);
|
||||
assert(ret == REDIS_ERR);
|
||||
} else {
|
||||
/* Disconnection is caused by an error, make sure that pending
|
||||
* callbacks cannot call new commands. */
|
||||
c->flags |= REDIS_DISCONNECTING;
|
||||
}
|
||||
|
||||
/* cleanup event library on disconnect.
|
||||
* this is safe to call multiple times */
|
||||
_EL_CLEANUP(ac);
|
||||
|
||||
/* For non-clean disconnects, __redisAsyncFree() will execute pending
|
||||
* callbacks with a NULL-reply. */
|
||||
if (!(c->flags & REDIS_NO_AUTO_FREE)) {
|
||||
__redisAsyncFree(ac);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tries to do a clean disconnect from Redis, meaning it stops new commands
|
||||
* from being issued, but tries to flush the output buffer and execute
|
||||
* callbacks for all remaining replies. When this function is called from a
|
||||
* callback, there might be more replies and we can safely defer disconnecting
|
||||
* to redisProcessCallbacks(). Otherwise, we can only disconnect immediately
|
||||
* when there are no pending callbacks. */
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
c->flags |= REDIS_DISCONNECTING;
|
||||
|
||||
/** unset the auto-free flag here, because disconnect undoes this */
|
||||
c->flags &= ~REDIS_NO_AUTO_FREE;
|
||||
if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) {
|
||||
redisContext *c = &(ac->c);
|
||||
dict *callbacks;
|
||||
redisCallback *cb;
|
||||
dictEntry *de;
|
||||
int pvariant;
|
||||
char *stype;
|
||||
sds sname;
|
||||
|
||||
/* Custom reply functions are not supported for pub/sub. This will fail
|
||||
* very hard when they are used... */
|
||||
if (reply->type == REDIS_REPLY_ARRAY || reply->type == REDIS_REPLY_PUSH) {
|
||||
assert(reply->elements >= 2);
|
||||
assert(reply->element[0]->type == REDIS_REPLY_STRING);
|
||||
stype = reply->element[0]->str;
|
||||
pvariant = (tolower(stype[0]) == 'p') ? 1 : 0;
|
||||
|
||||
if (pvariant)
|
||||
callbacks = ac->sub.patterns;
|
||||
else
|
||||
callbacks = ac->sub.channels;
|
||||
|
||||
/* Locate the right callback */
|
||||
assert(reply->element[1]->type == REDIS_REPLY_STRING);
|
||||
sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
|
||||
if (sname == NULL)
|
||||
goto oom;
|
||||
|
||||
de = dictFind(callbacks,sname);
|
||||
if (de != NULL) {
|
||||
cb = dictGetEntryVal(de);
|
||||
|
||||
/* If this is an subscribe reply decrease pending counter. */
|
||||
if (strcasecmp(stype+pvariant,"subscribe") == 0) {
|
||||
cb->pending_subs -= 1;
|
||||
}
|
||||
|
||||
memcpy(dstcb,cb,sizeof(*dstcb));
|
||||
|
||||
/* If this is an unsubscribe message, remove it. */
|
||||
if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
|
||||
if (cb->pending_subs == 0)
|
||||
dictDelete(callbacks,sname);
|
||||
|
||||
/* If this was the last unsubscribe message, revert to
|
||||
* non-subscribe mode. */
|
||||
assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
|
||||
|
||||
/* Unset subscribed flag only when no pipelined pending subscribe. */
|
||||
if (reply->element[2]->integer == 0
|
||||
&& dictSize(ac->sub.channels) == 0
|
||||
&& dictSize(ac->sub.patterns) == 0)
|
||||
c->flags &= ~REDIS_SUBSCRIBED;
|
||||
}
|
||||
}
|
||||
sdsfree(sname);
|
||||
} else {
|
||||
/* Shift callback for invalid commands. */
|
||||
__redisShiftCallback(&ac->sub.invalid,dstcb);
|
||||
}
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
#define redisIsSpontaneousPushReply(r) \
|
||||
(redisIsPushReply(r) && !redisIsSubscribeReply(r))
|
||||
|
||||
static int redisIsSubscribeReply(redisReply *reply) {
|
||||
char *str;
|
||||
size_t len, off;
|
||||
|
||||
/* We will always have at least one string with the subscribe/message type */
|
||||
if (reply->elements < 1 || reply->element[0]->type != REDIS_REPLY_STRING ||
|
||||
reply->element[0]->len < sizeof("message") - 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the string/len moving past 'p' if needed */
|
||||
off = tolower(reply->element[0]->str[0]) == 'p';
|
||||
str = reply->element[0]->str + off;
|
||||
len = reply->element[0]->len - off;
|
||||
|
||||
return !strncasecmp(str, "subscribe", len) ||
|
||||
!strncasecmp(str, "message", len);
|
||||
|
||||
}
|
||||
|
||||
void redisProcessCallbacks(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb = {NULL, NULL, 0, NULL};
|
||||
void *reply = NULL;
|
||||
int status;
|
||||
|
||||
while((status = redisGetReply(c,&reply)) == REDIS_OK) {
|
||||
if (reply == NULL) {
|
||||
/* When the connection is being disconnected and there are
|
||||
* no more replies, this is the cue to really disconnect. */
|
||||
if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0
|
||||
&& ac->replies.head == NULL) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If monitor mode, repush callback */
|
||||
if(c->flags & REDIS_MONITORING) {
|
||||
__redisPushCallback(&ac->replies,&cb);
|
||||
}
|
||||
|
||||
/* When the connection is not being disconnected, simply stop
|
||||
* trying to get replies and wait for the next loop tick. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send any non-subscribe related PUSH messages to our PUSH handler
|
||||
* while allowing subscribe related PUSH messages to pass through.
|
||||
* This allows existing code to be backward compatible and work in
|
||||
* either RESP2 or RESP3 mode. */
|
||||
if (redisIsSpontaneousPushReply(reply)) {
|
||||
__redisRunPushCallback(ac, reply);
|
||||
c->reader->fn->freeObject(reply);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Even if the context is subscribed, pending regular
|
||||
* callbacks will get a reply before pub/sub messages arrive. */
|
||||
if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
|
||||
/*
|
||||
* A spontaneous reply in a not-subscribed context can be the error
|
||||
* reply that is sent when a new connection exceeds the maximum
|
||||
* number of allowed connections on the server side.
|
||||
*
|
||||
* This is seen as an error instead of a regular reply because the
|
||||
* server closes the connection after sending it.
|
||||
*
|
||||
* To prevent the error from being overwritten by an EOF error the
|
||||
* connection is closed here. See issue #43.
|
||||
*
|
||||
* Another possibility is that the server is loading its dataset.
|
||||
* In this case we also want to close the connection, and have the
|
||||
* user wait until the server is ready to take our request.
|
||||
*/
|
||||
if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) {
|
||||
c->err = REDIS_ERR_OTHER;
|
||||
snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str);
|
||||
c->reader->fn->freeObject(reply);
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
}
|
||||
/* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */
|
||||
assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING));
|
||||
if(c->flags & REDIS_SUBSCRIBED)
|
||||
__redisGetSubscribeCallback(ac,reply,&cb);
|
||||
}
|
||||
|
||||
if (cb.fn != NULL) {
|
||||
__redisRunCallback(ac,&cb,reply);
|
||||
c->reader->fn->freeObject(reply);
|
||||
|
||||
/* Proceed with free'ing when redisAsyncFree() was called. */
|
||||
if (c->flags & REDIS_FREEING) {
|
||||
__redisAsyncFree(ac);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* No callback for this reply. This can either be a NULL callback,
|
||||
* or there were no callbacks to begin with. Either way, don't
|
||||
* abort with an error, but simply ignore it because the client
|
||||
* doesn't know what the server will spit out over the wire. */
|
||||
c->reader->fn->freeObject(reply);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disconnect when there was an error reading the reply */
|
||||
if (status != REDIS_OK)
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
static void __redisAsyncHandleConnectFailure(redisAsyncContext *ac) {
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
/* Internal helper function to detect socket status the first time a read or
|
||||
* write event fires. When connecting was not successful, the connect callback
|
||||
* is called with a REDIS_ERR status and the context is free'd. */
|
||||
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
|
||||
int completed = 0;
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (redisCheckConnectDone(c, &completed) == REDIS_ERR) {
|
||||
/* Error! */
|
||||
redisCheckSocketError(c);
|
||||
__redisAsyncHandleConnectFailure(ac);
|
||||
return REDIS_ERR;
|
||||
} else if (completed == 1) {
|
||||
/* connected! */
|
||||
if (c->connection_type == REDIS_CONN_TCP &&
|
||||
redisSetTcpNoDelay(c) == REDIS_ERR) {
|
||||
__redisAsyncHandleConnectFailure(ac);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (ac->onConnect) ac->onConnect(ac, REDIS_OK);
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
return REDIS_OK;
|
||||
} else {
|
||||
return REDIS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void redisAsyncRead(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (redisBufferRead(c) == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
/* Always re-schedule reads */
|
||||
_EL_ADD_READ(ac);
|
||||
redisProcessCallbacks(ac);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function should be called when the socket is readable.
|
||||
* It processes all replies that can be read and executes their callbacks.
|
||||
*/
|
||||
void redisAsyncHandleRead(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (!(c->flags & REDIS_CONNECTED)) {
|
||||
/* Abort connect was not successful. */
|
||||
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
|
||||
return;
|
||||
/* Try again later when the context is still not connected. */
|
||||
if (!(c->flags & REDIS_CONNECTED))
|
||||
return;
|
||||
}
|
||||
|
||||
c->funcs->async_read(ac);
|
||||
}
|
||||
|
||||
void redisAsyncWrite(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
int done = 0;
|
||||
|
||||
if (redisBufferWrite(c,&done) == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
/* Continue writing when not done, stop writing otherwise */
|
||||
if (!done)
|
||||
_EL_ADD_WRITE(ac);
|
||||
else
|
||||
_EL_DEL_WRITE(ac);
|
||||
|
||||
/* Always schedule reads after writes */
|
||||
_EL_ADD_READ(ac);
|
||||
}
|
||||
}
|
||||
|
||||
void redisAsyncHandleWrite(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
|
||||
if (!(c->flags & REDIS_CONNECTED)) {
|
||||
/* Abort connect was not successful. */
|
||||
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
|
||||
return;
|
||||
/* Try again later when the context is still not connected. */
|
||||
if (!(c->flags & REDIS_CONNECTED))
|
||||
return;
|
||||
}
|
||||
|
||||
c->funcs->async_write(ac);
|
||||
}
|
||||
|
||||
void redisAsyncHandleTimeout(redisAsyncContext *ac) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb;
|
||||
|
||||
if ((c->flags & REDIS_CONNECTED) && ac->replies.head == NULL) {
|
||||
/* Nothing to do - just an idle timeout */
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c->err) {
|
||||
__redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout");
|
||||
}
|
||||
|
||||
if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) {
|
||||
ac->onConnect(ac, REDIS_ERR);
|
||||
}
|
||||
|
||||
while (__redisShiftCallback(&ac->replies, &cb) == REDIS_OK) {
|
||||
__redisRunCallback(ac, &cb, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Don't automatically sever the connection,
|
||||
* rather, allow to ignore <x> responses before the queue is clear
|
||||
*/
|
||||
__redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
/* Sets a pointer to the first argument and its length starting at p. Returns
|
||||
* the number of bytes to skip to get to the following argument. */
|
||||
static const char *nextArgument(const char *start, const char **str, size_t *len) {
|
||||
const char *p = start;
|
||||
if (p[0] != '$') {
|
||||
p = strchr(p,'$');
|
||||
if (p == NULL) return NULL;
|
||||
}
|
||||
|
||||
*len = (int)strtol(p+1,NULL,10);
|
||||
p = strchr(p,'\r');
|
||||
assert(p);
|
||||
*str = p+2;
|
||||
return p+2+(*len)+2;
|
||||
}
|
||||
|
||||
/* Helper function for the redisAsyncCommand* family of functions. Writes a
|
||||
* formatted command to the output buffer and registers the provided callback
|
||||
* function with the context. */
|
||||
static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) {
|
||||
redisContext *c = &(ac->c);
|
||||
redisCallback cb;
|
||||
struct dict *cbdict;
|
||||
dictEntry *de;
|
||||
redisCallback *existcb;
|
||||
int pvariant, hasnext;
|
||||
const char *cstr, *astr;
|
||||
size_t clen, alen;
|
||||
const char *p;
|
||||
sds sname;
|
||||
int ret;
|
||||
|
||||
/* Don't accept new commands when the connection is about to be closed. */
|
||||
if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR;
|
||||
|
||||
/* Setup callback */
|
||||
cb.fn = fn;
|
||||
cb.privdata = privdata;
|
||||
cb.pending_subs = 1;
|
||||
|
||||
/* Find out which command will be appended. */
|
||||
p = nextArgument(cmd,&cstr,&clen);
|
||||
assert(p != NULL);
|
||||
hasnext = (p[0] == '$');
|
||||
pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0;
|
||||
cstr += pvariant;
|
||||
clen -= pvariant;
|
||||
|
||||
if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) {
|
||||
c->flags |= REDIS_SUBSCRIBED;
|
||||
|
||||
/* Add every channel/pattern to the list of subscription callbacks. */
|
||||
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
|
||||
sname = sdsnewlen(astr,alen);
|
||||
if (sname == NULL)
|
||||
goto oom;
|
||||
|
||||
if (pvariant)
|
||||
cbdict = ac->sub.patterns;
|
||||
else
|
||||
cbdict = ac->sub.channels;
|
||||
|
||||
de = dictFind(cbdict,sname);
|
||||
|
||||
if (de != NULL) {
|
||||
existcb = dictGetEntryVal(de);
|
||||
cb.pending_subs = existcb->pending_subs + 1;
|
||||
}
|
||||
|
||||
ret = dictReplace(cbdict,sname,&cb);
|
||||
|
||||
if (ret == 0) sdsfree(sname);
|
||||
}
|
||||
} else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) {
|
||||
/* It is only useful to call (P)UNSUBSCRIBE when the context is
|
||||
* subscribed to one or more channels or patterns. */
|
||||
if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR;
|
||||
|
||||
/* (P)UNSUBSCRIBE does not have its own response: every channel or
|
||||
* pattern that is unsubscribed will receive a message. This means we
|
||||
* should not append a callback function for this command. */
|
||||
} else if(strncasecmp(cstr,"monitor\r\n",9) == 0) {
|
||||
/* Set monitor flag and push callback */
|
||||
c->flags |= REDIS_MONITORING;
|
||||
__redisPushCallback(&ac->replies,&cb);
|
||||
} else {
|
||||
if (c->flags & REDIS_SUBSCRIBED)
|
||||
/* This will likely result in an error reply, but it needs to be
|
||||
* received and passed to the callback. */
|
||||
__redisPushCallback(&ac->sub.invalid,&cb);
|
||||
else
|
||||
__redisPushCallback(&ac->replies,&cb);
|
||||
}
|
||||
|
||||
__redisAppendCommand(c,cmd,len);
|
||||
|
||||
/* Always schedule a write when the write buffer is non-empty */
|
||||
_EL_ADD_WRITE(ac);
|
||||
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) {
|
||||
char *cmd;
|
||||
int len;
|
||||
int status;
|
||||
len = redisvFormatCommand(&cmd,format,ap);
|
||||
|
||||
/* We don't want to pass -1 or -2 to future functions as a length. */
|
||||
if (len < 0)
|
||||
return REDIS_ERR;
|
||||
|
||||
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
hi_free(cmd);
|
||||
return status;
|
||||
}
|
||||
|
||||
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) {
|
||||
va_list ap;
|
||||
int status;
|
||||
va_start(ap,format);
|
||||
status = redisvAsyncCommand(ac,fn,privdata,format,ap);
|
||||
va_end(ap);
|
||||
return status;
|
||||
}
|
||||
|
||||
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
|
||||
sds cmd;
|
||||
int len;
|
||||
int status;
|
||||
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
|
||||
if (len < 0)
|
||||
return REDIS_ERR;
|
||||
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
sdsfree(cmd);
|
||||
return status;
|
||||
}
|
||||
|
||||
int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) {
|
||||
int status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
|
||||
return status;
|
||||
}
|
||||
|
||||
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn) {
|
||||
redisAsyncPushFn *old = ac->push_cb;
|
||||
ac->push_cb = fn;
|
||||
return old;
|
||||
}
|
||||
|
||||
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
|
||||
if (!ac->c.command_timeout) {
|
||||
ac->c.command_timeout = hi_calloc(1, sizeof(tv));
|
||||
if (ac->c.command_timeout == NULL) {
|
||||
__redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory");
|
||||
__redisAsyncCopyError(ac);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (tv.tv_sec != ac->c.command_timeout->tv_sec ||
|
||||
tv.tv_usec != ac->c.command_timeout->tv_usec)
|
||||
{
|
||||
*ac->c.command_timeout = tv;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
147
ext/hiredis-1.0.2/async.h
Normal file
147
ext/hiredis-1.0.2/async.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_ASYNC_H
|
||||
#define __HIREDIS_ASYNC_H
|
||||
#include "hiredis.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
|
||||
struct dict; /* dictionary header is included in async.c */
|
||||
|
||||
/* Reply callback prototype and container */
|
||||
typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
|
||||
typedef struct redisCallback {
|
||||
struct redisCallback *next; /* simple singly linked list */
|
||||
redisCallbackFn *fn;
|
||||
int pending_subs;
|
||||
void *privdata;
|
||||
} redisCallback;
|
||||
|
||||
/* List of callbacks for either regular replies or pub/sub */
|
||||
typedef struct redisCallbackList {
|
||||
redisCallback *head, *tail;
|
||||
} redisCallbackList;
|
||||
|
||||
/* Connection callback prototypes */
|
||||
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void(redisTimerCallback)(void *timer, void *privdata);
|
||||
|
||||
/* Context for an async connection to Redis */
|
||||
typedef struct redisAsyncContext {
|
||||
/* Hold the regular context, so it can be realloc'ed. */
|
||||
redisContext c;
|
||||
|
||||
/* Setup error flags so they can be used directly. */
|
||||
int err;
|
||||
char *errstr;
|
||||
|
||||
/* Not used by hiredis */
|
||||
void *data;
|
||||
void (*dataCleanup)(void *privdata);
|
||||
|
||||
/* Event library data and hooks */
|
||||
struct {
|
||||
void *data;
|
||||
|
||||
/* Hooks that are called when the library expects to start
|
||||
* reading/writing. These functions should be idempotent. */
|
||||
void (*addRead)(void *privdata);
|
||||
void (*delRead)(void *privdata);
|
||||
void (*addWrite)(void *privdata);
|
||||
void (*delWrite)(void *privdata);
|
||||
void (*cleanup)(void *privdata);
|
||||
void (*scheduleTimer)(void *privdata, struct timeval tv);
|
||||
} ev;
|
||||
|
||||
/* Called when either the connection is terminated due to an error or per
|
||||
* user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
|
||||
redisDisconnectCallback *onDisconnect;
|
||||
|
||||
/* Called when the first write event was received. */
|
||||
redisConnectCallback *onConnect;
|
||||
|
||||
/* Regular command callbacks */
|
||||
redisCallbackList replies;
|
||||
|
||||
/* Address used for connect() */
|
||||
struct sockaddr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Subscription callbacks */
|
||||
struct {
|
||||
redisCallbackList invalid;
|
||||
struct dict *channels;
|
||||
struct dict *patterns;
|
||||
} sub;
|
||||
|
||||
/* Any configured RESP3 PUSH handler */
|
||||
redisAsyncPushFn *push_cb;
|
||||
} redisAsyncContext;
|
||||
|
||||
/* Functions that proxy to hiredis */
|
||||
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options);
|
||||
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
|
||||
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
|
||||
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
||||
const char *source_addr);
|
||||
redisAsyncContext *redisAsyncConnectUnix(const char *path);
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
|
||||
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn);
|
||||
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisAsyncFree(redisAsyncContext *ac);
|
||||
|
||||
/* Handle read/write events */
|
||||
void redisAsyncHandleRead(redisAsyncContext *ac);
|
||||
void redisAsyncHandleWrite(redisAsyncContext *ac);
|
||||
void redisAsyncHandleTimeout(redisAsyncContext *ac);
|
||||
void redisAsyncRead(redisAsyncContext *ac);
|
||||
void redisAsyncWrite(redisAsyncContext *ac);
|
||||
|
||||
/* Command functions for an async context. Write the command to the
|
||||
* output buffer and register the provided callback. */
|
||||
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
|
||||
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
|
||||
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
|
||||
int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
75
ext/hiredis-1.0.2/async_private.h
Normal file
75
ext/hiredis-1.0.2/async_private.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_ASYNC_PRIVATE_H
|
||||
#define __HIREDIS_ASYNC_PRIVATE_H
|
||||
|
||||
#define _EL_ADD_READ(ctx) \
|
||||
do { \
|
||||
refreshTimeout(ctx); \
|
||||
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
|
||||
} while (0)
|
||||
#define _EL_DEL_READ(ctx) do { \
|
||||
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_ADD_WRITE(ctx) \
|
||||
do { \
|
||||
refreshTimeout(ctx); \
|
||||
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
|
||||
} while (0)
|
||||
#define _EL_DEL_WRITE(ctx) do { \
|
||||
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_CLEANUP(ctx) do { \
|
||||
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
|
||||
ctx->ev.cleanup = NULL; \
|
||||
} while(0);
|
||||
|
||||
static inline void refreshTimeout(redisAsyncContext *ctx) {
|
||||
#define REDIS_TIMER_ISSET(tvp) \
|
||||
(tvp && ((tvp)->tv_sec || (tvp)->tv_usec))
|
||||
|
||||
#define REDIS_EL_TIMER(ac, tvp) \
|
||||
if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \
|
||||
(ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \
|
||||
}
|
||||
|
||||
if (ctx->c.flags & REDIS_CONNECTED) {
|
||||
REDIS_EL_TIMER(ctx, ctx->c.command_timeout);
|
||||
} else {
|
||||
REDIS_EL_TIMER(ctx, ctx->c.connect_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
void __redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisProcessCallbacks(redisAsyncContext *ac);
|
||||
|
||||
#endif /* __HIREDIS_ASYNC_PRIVATE_H */
|
352
ext/hiredis-1.0.2/dict.c
Normal file
352
ext/hiredis-1.0.2/dict.c
Normal file
@ -0,0 +1,352 @@
|
||||
/* Hash table implementation.
|
||||
*
|
||||
* This file implements in memory hash tables with insert/del/replace/find/
|
||||
* get-random-element operations. Hash tables will auto resize if needed
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "alloc.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include "dict.h"
|
||||
|
||||
/* -------------------------- private prototypes ---------------------------- */
|
||||
|
||||
static int _dictExpandIfNeeded(dict *ht);
|
||||
static unsigned long _dictNextPower(unsigned long size);
|
||||
static int _dictKeyIndex(dict *ht, const void *key);
|
||||
static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
|
||||
|
||||
/* -------------------------- hash functions -------------------------------- */
|
||||
|
||||
/* Generic hash function (a popular one from Bernstein).
|
||||
* I tested a few and this was the best. */
|
||||
static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
|
||||
unsigned int hash = 5381;
|
||||
|
||||
while (len--)
|
||||
hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* ----------------------------- API implementation ------------------------- */
|
||||
|
||||
/* Reset an hashtable already initialized with ht_init().
|
||||
* NOTE: This function should only called by ht_destroy(). */
|
||||
static void _dictReset(dict *ht) {
|
||||
ht->table = NULL;
|
||||
ht->size = 0;
|
||||
ht->sizemask = 0;
|
||||
ht->used = 0;
|
||||
}
|
||||
|
||||
/* Create a new hash table */
|
||||
static dict *dictCreate(dictType *type, void *privDataPtr) {
|
||||
dict *ht = hi_malloc(sizeof(*ht));
|
||||
if (ht == NULL)
|
||||
return NULL;
|
||||
|
||||
_dictInit(ht,type,privDataPtr);
|
||||
return ht;
|
||||
}
|
||||
|
||||
/* Initialize the hash table */
|
||||
static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
|
||||
_dictReset(ht);
|
||||
ht->type = type;
|
||||
ht->privdata = privDataPtr;
|
||||
return DICT_OK;
|
||||
}
|
||||
|
||||
/* Expand or create the hashtable */
|
||||
static int dictExpand(dict *ht, unsigned long size) {
|
||||
dict n; /* the new hashtable */
|
||||
unsigned long realsize = _dictNextPower(size), i;
|
||||
|
||||
/* the size is invalid if it is smaller than the number of
|
||||
* elements already inside the hashtable */
|
||||
if (ht->used > size)
|
||||
return DICT_ERR;
|
||||
|
||||
_dictInit(&n, ht->type, ht->privdata);
|
||||
n.size = realsize;
|
||||
n.sizemask = realsize-1;
|
||||
n.table = hi_calloc(realsize,sizeof(dictEntry*));
|
||||
if (n.table == NULL)
|
||||
return DICT_ERR;
|
||||
|
||||
/* Copy all the elements from the old to the new table:
|
||||
* note that if the old hash table is empty ht->size is zero,
|
||||
* so dictExpand just creates an hash table. */
|
||||
n.used = ht->used;
|
||||
for (i = 0; i < ht->size && ht->used > 0; i++) {
|
||||
dictEntry *he, *nextHe;
|
||||
|
||||
if (ht->table[i] == NULL) continue;
|
||||
|
||||
/* For each hash entry on this slot... */
|
||||
he = ht->table[i];
|
||||
while(he) {
|
||||
unsigned int h;
|
||||
|
||||
nextHe = he->next;
|
||||
/* Get the new element index */
|
||||
h = dictHashKey(ht, he->key) & n.sizemask;
|
||||
he->next = n.table[h];
|
||||
n.table[h] = he;
|
||||
ht->used--;
|
||||
/* Pass to the next element */
|
||||
he = nextHe;
|
||||
}
|
||||
}
|
||||
assert(ht->used == 0);
|
||||
hi_free(ht->table);
|
||||
|
||||
/* Remap the new hashtable in the old */
|
||||
*ht = n;
|
||||
return DICT_OK;
|
||||
}
|
||||
|
||||
/* Add an element to the target hash table */
|
||||
static int dictAdd(dict *ht, void *key, void *val) {
|
||||
int index;
|
||||
dictEntry *entry;
|
||||
|
||||
/* Get the index of the new element, or -1 if
|
||||
* the element already exists. */
|
||||
if ((index = _dictKeyIndex(ht, key)) == -1)
|
||||
return DICT_ERR;
|
||||
|
||||
/* Allocates the memory and stores key */
|
||||
entry = hi_malloc(sizeof(*entry));
|
||||
if (entry == NULL)
|
||||
return DICT_ERR;
|
||||
|
||||
entry->next = ht->table[index];
|
||||
ht->table[index] = entry;
|
||||
|
||||
/* Set the hash entry fields. */
|
||||
dictSetHashKey(ht, entry, key);
|
||||
dictSetHashVal(ht, entry, val);
|
||||
ht->used++;
|
||||
return DICT_OK;
|
||||
}
|
||||
|
||||
/* Add an element, discarding the old if the key already exists.
|
||||
* Return 1 if the key was added from scratch, 0 if there was already an
|
||||
* element with such key and dictReplace() just performed a value update
|
||||
* operation. */
|
||||
static int dictReplace(dict *ht, void *key, void *val) {
|
||||
dictEntry *entry, auxentry;
|
||||
|
||||
/* Try to add the element. If the key
|
||||
* does not exists dictAdd will succeed. */
|
||||
if (dictAdd(ht, key, val) == DICT_OK)
|
||||
return 1;
|
||||
/* It already exists, get the entry */
|
||||
entry = dictFind(ht, key);
|
||||
if (entry == NULL)
|
||||
return 0;
|
||||
|
||||
/* Free the old value and set the new one */
|
||||
/* Set the new value and free the old one. Note that it is important
|
||||
* to do that in this order, as the value may just be exactly the same
|
||||
* as the previous one. In this context, think to reference counting,
|
||||
* you want to increment (set), and then decrement (free), and not the
|
||||
* reverse. */
|
||||
auxentry = *entry;
|
||||
dictSetHashVal(ht, entry, val);
|
||||
dictFreeEntryVal(ht, &auxentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search and remove an element */
|
||||
static int dictDelete(dict *ht, const void *key) {
|
||||
unsigned int h;
|
||||
dictEntry *de, *prevde;
|
||||
|
||||
if (ht->size == 0)
|
||||
return DICT_ERR;
|
||||
h = dictHashKey(ht, key) & ht->sizemask;
|
||||
de = ht->table[h];
|
||||
|
||||
prevde = NULL;
|
||||
while(de) {
|
||||
if (dictCompareHashKeys(ht,key,de->key)) {
|
||||
/* Unlink the element from the list */
|
||||
if (prevde)
|
||||
prevde->next = de->next;
|
||||
else
|
||||
ht->table[h] = de->next;
|
||||
|
||||
dictFreeEntryKey(ht,de);
|
||||
dictFreeEntryVal(ht,de);
|
||||
hi_free(de);
|
||||
ht->used--;
|
||||
return DICT_OK;
|
||||
}
|
||||
prevde = de;
|
||||
de = de->next;
|
||||
}
|
||||
return DICT_ERR; /* not found */
|
||||
}
|
||||
|
||||
/* Destroy an entire hash table */
|
||||
static int _dictClear(dict *ht) {
|
||||
unsigned long i;
|
||||
|
||||
/* Free all the elements */
|
||||
for (i = 0; i < ht->size && ht->used > 0; i++) {
|
||||
dictEntry *he, *nextHe;
|
||||
|
||||
if ((he = ht->table[i]) == NULL) continue;
|
||||
while(he) {
|
||||
nextHe = he->next;
|
||||
dictFreeEntryKey(ht, he);
|
||||
dictFreeEntryVal(ht, he);
|
||||
hi_free(he);
|
||||
ht->used--;
|
||||
he = nextHe;
|
||||
}
|
||||
}
|
||||
/* Free the table and the allocated cache structure */
|
||||
hi_free(ht->table);
|
||||
/* Re-initialize the table */
|
||||
_dictReset(ht);
|
||||
return DICT_OK; /* never fails */
|
||||
}
|
||||
|
||||
/* Clear & Release the hash table */
|
||||
static void dictRelease(dict *ht) {
|
||||
_dictClear(ht);
|
||||
hi_free(ht);
|
||||
}
|
||||
|
||||
static dictEntry *dictFind(dict *ht, const void *key) {
|
||||
dictEntry *he;
|
||||
unsigned int h;
|
||||
|
||||
if (ht->size == 0) return NULL;
|
||||
h = dictHashKey(ht, key) & ht->sizemask;
|
||||
he = ht->table[h];
|
||||
while(he) {
|
||||
if (dictCompareHashKeys(ht, key, he->key))
|
||||
return he;
|
||||
he = he->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dictIterator *dictGetIterator(dict *ht) {
|
||||
dictIterator *iter = hi_malloc(sizeof(*iter));
|
||||
if (iter == NULL)
|
||||
return NULL;
|
||||
|
||||
iter->ht = ht;
|
||||
iter->index = -1;
|
||||
iter->entry = NULL;
|
||||
iter->nextEntry = NULL;
|
||||
return iter;
|
||||
}
|
||||
|
||||
static dictEntry *dictNext(dictIterator *iter) {
|
||||
while (1) {
|
||||
if (iter->entry == NULL) {
|
||||
iter->index++;
|
||||
if (iter->index >=
|
||||
(signed)iter->ht->size) break;
|
||||
iter->entry = iter->ht->table[iter->index];
|
||||
} else {
|
||||
iter->entry = iter->nextEntry;
|
||||
}
|
||||
if (iter->entry) {
|
||||
/* We need to save the 'next' here, the iterator user
|
||||
* may delete the entry we are returning. */
|
||||
iter->nextEntry = iter->entry->next;
|
||||
return iter->entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dictReleaseIterator(dictIterator *iter) {
|
||||
hi_free(iter);
|
||||
}
|
||||
|
||||
/* ------------------------- private functions ------------------------------ */
|
||||
|
||||
/* Expand the hash table if needed */
|
||||
static int _dictExpandIfNeeded(dict *ht) {
|
||||
/* If the hash table is empty expand it to the initial size,
|
||||
* if the table is "full" double its size. */
|
||||
if (ht->size == 0)
|
||||
return dictExpand(ht, DICT_HT_INITIAL_SIZE);
|
||||
if (ht->used == ht->size)
|
||||
return dictExpand(ht, ht->size*2);
|
||||
return DICT_OK;
|
||||
}
|
||||
|
||||
/* Our hash table capability is a power of two */
|
||||
static unsigned long _dictNextPower(unsigned long size) {
|
||||
unsigned long i = DICT_HT_INITIAL_SIZE;
|
||||
|
||||
if (size >= LONG_MAX) return LONG_MAX;
|
||||
while(1) {
|
||||
if (i >= size)
|
||||
return i;
|
||||
i *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the index of a free slot that can be populated with
|
||||
* an hash entry for the given 'key'.
|
||||
* If the key already exists, -1 is returned. */
|
||||
static int _dictKeyIndex(dict *ht, const void *key) {
|
||||
unsigned int h;
|
||||
dictEntry *he;
|
||||
|
||||
/* Expand the hashtable if needed */
|
||||
if (_dictExpandIfNeeded(ht) == DICT_ERR)
|
||||
return -1;
|
||||
/* Compute the key hash value */
|
||||
h = dictHashKey(ht, key) & ht->sizemask;
|
||||
/* Search if this slot does not already contain the given key */
|
||||
he = ht->table[h];
|
||||
while(he) {
|
||||
if (dictCompareHashKeys(ht, key, he->key))
|
||||
return -1;
|
||||
he = he->next;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
126
ext/hiredis-1.0.2/dict.h
Normal file
126
ext/hiredis-1.0.2/dict.h
Normal file
@ -0,0 +1,126 @@
|
||||
/* Hash table implementation.
|
||||
*
|
||||
* This file implements in memory hash tables with insert/del/replace/find/
|
||||
* get-random-element operations. Hash tables will auto resize if needed
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DICT_H
|
||||
#define __DICT_H
|
||||
|
||||
#define DICT_OK 0
|
||||
#define DICT_ERR 1
|
||||
|
||||
/* Unused arguments generate annoying warnings... */
|
||||
#define DICT_NOTUSED(V) ((void) V)
|
||||
|
||||
typedef struct dictEntry {
|
||||
void *key;
|
||||
void *val;
|
||||
struct dictEntry *next;
|
||||
} dictEntry;
|
||||
|
||||
typedef struct dictType {
|
||||
unsigned int (*hashFunction)(const void *key);
|
||||
void *(*keyDup)(void *privdata, const void *key);
|
||||
void *(*valDup)(void *privdata, const void *obj);
|
||||
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
|
||||
void (*keyDestructor)(void *privdata, void *key);
|
||||
void (*valDestructor)(void *privdata, void *obj);
|
||||
} dictType;
|
||||
|
||||
typedef struct dict {
|
||||
dictEntry **table;
|
||||
dictType *type;
|
||||
unsigned long size;
|
||||
unsigned long sizemask;
|
||||
unsigned long used;
|
||||
void *privdata;
|
||||
} dict;
|
||||
|
||||
typedef struct dictIterator {
|
||||
dict *ht;
|
||||
int index;
|
||||
dictEntry *entry, *nextEntry;
|
||||
} dictIterator;
|
||||
|
||||
/* This is the initial size of every hash table */
|
||||
#define DICT_HT_INITIAL_SIZE 4
|
||||
|
||||
/* ------------------------------- Macros ------------------------------------*/
|
||||
#define dictFreeEntryVal(ht, entry) \
|
||||
if ((ht)->type->valDestructor) \
|
||||
(ht)->type->valDestructor((ht)->privdata, (entry)->val)
|
||||
|
||||
#define dictSetHashVal(ht, entry, _val_) do { \
|
||||
if ((ht)->type->valDup) \
|
||||
entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
|
||||
else \
|
||||
entry->val = (_val_); \
|
||||
} while(0)
|
||||
|
||||
#define dictFreeEntryKey(ht, entry) \
|
||||
if ((ht)->type->keyDestructor) \
|
||||
(ht)->type->keyDestructor((ht)->privdata, (entry)->key)
|
||||
|
||||
#define dictSetHashKey(ht, entry, _key_) do { \
|
||||
if ((ht)->type->keyDup) \
|
||||
entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
|
||||
else \
|
||||
entry->key = (_key_); \
|
||||
} while(0)
|
||||
|
||||
#define dictCompareHashKeys(ht, key1, key2) \
|
||||
(((ht)->type->keyCompare) ? \
|
||||
(ht)->type->keyCompare((ht)->privdata, key1, key2) : \
|
||||
(key1) == (key2))
|
||||
|
||||
#define dictHashKey(ht, key) (ht)->type->hashFunction(key)
|
||||
|
||||
#define dictGetEntryKey(he) ((he)->key)
|
||||
#define dictGetEntryVal(he) ((he)->val)
|
||||
#define dictSlots(ht) ((ht)->size)
|
||||
#define dictSize(ht) ((ht)->used)
|
||||
|
||||
/* API */
|
||||
static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
|
||||
static dict *dictCreate(dictType *type, void *privDataPtr);
|
||||
static int dictExpand(dict *ht, unsigned long size);
|
||||
static int dictAdd(dict *ht, void *key, void *val);
|
||||
static int dictReplace(dict *ht, void *key, void *val);
|
||||
static int dictDelete(dict *ht, const void *key);
|
||||
static void dictRelease(dict *ht);
|
||||
static dictEntry * dictFind(dict *ht, const void *key);
|
||||
static dictIterator *dictGetIterator(dict *ht);
|
||||
static dictEntry *dictNext(dictIterator *iter);
|
||||
static void dictReleaseIterator(dictIterator *iter);
|
||||
|
||||
#endif /* __DICT_H */
|
49
ext/hiredis-1.0.2/examples/CMakeLists.txt
Normal file
49
ext/hiredis-1.0.2/examples/CMakeLists.txt
Normal file
@ -0,0 +1,49 @@
|
||||
INCLUDE(FindPkgConfig)
|
||||
# Check for GLib
|
||||
|
||||
PKG_CHECK_MODULES(GLIB2 glib-2.0)
|
||||
if (GLIB2_FOUND)
|
||||
INCLUDE_DIRECTORIES(${GLIB2_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${GLIB2_LIBRARY_DIRS})
|
||||
ADD_EXECUTABLE(example-glib example-glib.c)
|
||||
TARGET_LINK_LIBRARIES(example-glib hiredis ${GLIB2_LIBRARIES})
|
||||
ENDIF(GLIB2_FOUND)
|
||||
|
||||
FIND_PATH(LIBEV ev.h
|
||||
HINTS /usr/local /usr/opt/local
|
||||
ENV LIBEV_INCLUDE_DIR)
|
||||
|
||||
if (LIBEV)
|
||||
# Just compile and link with libev
|
||||
ADD_EXECUTABLE(example-libev example-libev.c)
|
||||
TARGET_LINK_LIBRARIES(example-libev hiredis ev)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(LIBEVENT event.h)
|
||||
if (LIBEVENT)
|
||||
ADD_EXECUTABLE(example-libevent example-libevent)
|
||||
TARGET_LINK_LIBRARIES(example-libevent hiredis event)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(LIBUV uv.h)
|
||||
IF (LIBUV)
|
||||
ADD_EXECUTABLE(example-libuv example-libuv.c)
|
||||
TARGET_LINK_LIBRARIES(example-libuv hiredis uv)
|
||||
ENDIF()
|
||||
|
||||
IF (APPLE)
|
||||
FIND_LIBRARY(CF CoreFoundation)
|
||||
ADD_EXECUTABLE(example-macosx example-macosx.c)
|
||||
TARGET_LINK_LIBRARIES(example-macosx hiredis ${CF})
|
||||
ENDIF()
|
||||
|
||||
IF (ENABLE_SSL)
|
||||
ADD_EXECUTABLE(example-ssl example-ssl.c)
|
||||
TARGET_LINK_LIBRARIES(example-ssl hiredis hiredis_ssl)
|
||||
ENDIF()
|
||||
|
||||
ADD_EXECUTABLE(example example.c)
|
||||
TARGET_LINK_LIBRARIES(example hiredis)
|
||||
|
||||
ADD_EXECUTABLE(example-push example-push.c)
|
||||
TARGET_LINK_LIBRARIES(example-push hiredis)
|
62
ext/hiredis-1.0.2/examples/example-ae.c
Normal file
62
ext/hiredis-1.0.2/examples/example-ae.c
Normal file
@ -0,0 +1,62 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/ae.h>
|
||||
|
||||
/* Put event loop in the global scope, so it can be explicitly stopped */
|
||||
static aeEventLoop *loop;
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
aeStop(loop);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
aeStop(loop);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Disconnected...\n");
|
||||
aeStop(loop);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
loop = aeCreateEventLoop(64);
|
||||
redisAeAttach(loop, c);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
aeMain(loop);
|
||||
return 0;
|
||||
}
|
||||
|
73
ext/hiredis-1.0.2/examples/example-glib.c
Normal file
73
ext/hiredis-1.0.2/examples/example-glib.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/glib.h>
|
||||
|
||||
static GMainLoop *mainloop;
|
||||
|
||||
static void
|
||||
connect_cb (const redisAsyncContext *ac G_GNUC_UNUSED,
|
||||
int status)
|
||||
{
|
||||
if (status != REDIS_OK) {
|
||||
g_printerr("Failed to connect: %s\n", ac->errstr);
|
||||
g_main_loop_quit(mainloop);
|
||||
} else {
|
||||
g_printerr("Connected...\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_cb (const redisAsyncContext *ac G_GNUC_UNUSED,
|
||||
int status)
|
||||
{
|
||||
if (status != REDIS_OK) {
|
||||
g_error("Failed to disconnect: %s", ac->errstr);
|
||||
} else {
|
||||
g_printerr("Disconnected...\n");
|
||||
g_main_loop_quit(mainloop);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
command_cb(redisAsyncContext *ac,
|
||||
gpointer r,
|
||||
gpointer user_data G_GNUC_UNUSED)
|
||||
{
|
||||
redisReply *reply = r;
|
||||
|
||||
if (reply) {
|
||||
g_print("REPLY: %s\n", reply->str);
|
||||
}
|
||||
|
||||
redisAsyncDisconnect(ac);
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc G_GNUC_UNUSED,
|
||||
gchar *argv[] G_GNUC_UNUSED)
|
||||
{
|
||||
redisAsyncContext *ac;
|
||||
GMainContext *context = NULL;
|
||||
GSource *source;
|
||||
|
||||
ac = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (ac->err) {
|
||||
g_printerr("%s\n", ac->errstr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
source = redis_source_new(ac);
|
||||
mainloop = g_main_loop_new(context, FALSE);
|
||||
g_source_attach(source, context);
|
||||
|
||||
redisAsyncSetConnectCallback(ac, connect_cb);
|
||||
redisAsyncSetDisconnectCallback(ac, disconnect_cb);
|
||||
redisAsyncCommand(ac, command_cb, NULL, "SET key 1234");
|
||||
redisAsyncCommand(ac, command_cb, NULL, "GET key");
|
||||
|
||||
g_main_loop_run(mainloop);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
60
ext/hiredis-1.0.2/examples/example-ivykis.c
Normal file
60
ext/hiredis-1.0.2/examples/example-ivykis.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/ivykis.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
iv_init();
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisIvykisAttach(c);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
|
||||
iv_main();
|
||||
|
||||
iv_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
54
ext/hiredis-1.0.2/examples/example-libev.c
Normal file
54
ext/hiredis-1.0.2/examples/example-libev.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/libev.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisLibevAttach(EV_DEFAULT_ c);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
ev_loop(EV_DEFAULT_ 0);
|
||||
return 0;
|
||||
}
|
90
ext/hiredis-1.0.2/examples/example-libevent-ssl.c
Normal file
90
ext/hiredis-1.0.2/examples/example-libevent-ssl.c
Normal file
@ -0,0 +1,90 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <hiredis_ssl.h>
|
||||
#include <async.h>
|
||||
#include <adapters/libevent.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
struct event_base *base = event_base_new();
|
||||
if (argc < 5) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <key> <host> <port> <cert> <certKey> [ca]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *value = argv[1];
|
||||
size_t nvalue = strlen(value);
|
||||
|
||||
const char *hostname = argv[2];
|
||||
int port = atoi(argv[3]);
|
||||
|
||||
const char *cert = argv[4];
|
||||
const char *certKey = argv[5];
|
||||
const char *caCert = argc > 5 ? argv[6] : NULL;
|
||||
|
||||
redisSSLContext *ssl;
|
||||
redisSSLContextError ssl_error;
|
||||
|
||||
redisInitOpenSSL();
|
||||
|
||||
ssl = redisCreateSSLContext(caCert, NULL,
|
||||
cert, certKey, NULL, &ssl_error);
|
||||
if (!ssl) {
|
||||
printf("Error: %s\n", redisSSLContextGetError(ssl_error));
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect(hostname, port);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
if (redisInitiateSSLWithContext(&c->c, ssl) != REDIS_OK) {
|
||||
printf("SSL Error!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
redisLibeventAttach(c,base);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue);
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
event_base_dispatch(base);
|
||||
|
||||
redisFreeSSLContext(ssl);
|
||||
return 0;
|
||||
}
|
67
ext/hiredis-1.0.2/examples/example-libevent.c
Normal file
67
ext/hiredis-1.0.2/examples/example-libevent.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/libevent.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) {
|
||||
if (c->errstr) {
|
||||
printf("errstr: %s\n", c->errstr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
struct event_base *base = event_base_new();
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
|
||||
struct timeval tv = {0};
|
||||
tv.tv_sec = 1;
|
||||
options.connect_timeout = &tv;
|
||||
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisLibeventAttach(c,base);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
event_base_dispatch(base);
|
||||
return 0;
|
||||
}
|
56
ext/hiredis-1.0.2/examples/example-libuv.c
Normal file
56
ext/hiredis-1.0.2/examples/example-libuv.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/libuv.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisLibuvAttach(c,loop);
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
return 0;
|
||||
}
|
66
ext/hiredis-1.0.2/examples/example-macosx.c
Normal file
66
ext/hiredis-1.0.2/examples/example-macosx.c
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// Created by Дмитрий Бахвалов on 13.07.15.
|
||||
// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <async.h>
|
||||
#include <adapters/macosx.h>
|
||||
|
||||
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
|
||||
redisReply *reply = r;
|
||||
if (reply == NULL) return;
|
||||
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
|
||||
|
||||
/* Disconnect after receiving the reply to GET */
|
||||
redisAsyncDisconnect(c);
|
||||
}
|
||||
|
||||
void connectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
printf("Connected...\n");
|
||||
}
|
||||
|
||||
void disconnectCallback(const redisAsyncContext *c, int status) {
|
||||
if (status != REDIS_OK) {
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return;
|
||||
}
|
||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||
printf("Disconnected...\n");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
CFRunLoopRef loop = CFRunLoopGetCurrent();
|
||||
if( !loop ) {
|
||||
printf("Error: Cannot get current run loop\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
|
||||
if (c->err) {
|
||||
/* Let *c leak for now... */
|
||||
printf("Error: %s\n", c->errstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
redisMacOSAttach(c, loop);
|
||||
|
||||
redisAsyncSetConnectCallback(c,connectCallback);
|
||||
redisAsyncSetDisconnectCallback(c,disconnectCallback);
|
||||
|
||||
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
|
||||
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
|
||||
|
||||
CFRunLoopRun();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
160
ext/hiredis-1.0.2/examples/example-push.c
Normal file
160
ext/hiredis-1.0.2/examples/example-push.c
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <hiredis.h>
|
||||
#include <win32.h>
|
||||
|
||||
#define KEY_COUNT 5
|
||||
|
||||
#define panicAbort(fmt, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); \
|
||||
exit(-1); \
|
||||
} while (0)
|
||||
|
||||
static void assertReplyAndFree(redisContext *context, redisReply *reply, int type) {
|
||||
if (reply == NULL)
|
||||
panicAbort("NULL reply from server (error: %s)", context->errstr);
|
||||
|
||||
if (reply->type != type) {
|
||||
if (reply->type == REDIS_REPLY_ERROR)
|
||||
fprintf(stderr, "Redis Error: %s\n", reply->str);
|
||||
|
||||
panicAbort("Expected reply type %d but got type %d", type, reply->type);
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Switch to the RESP3 protocol and enable client tracking */
|
||||
static void enableClientTracking(redisContext *c) {
|
||||
redisReply *reply = redisCommand(c, "HELLO 3");
|
||||
if (reply == NULL || c->err) {
|
||||
panicAbort("NULL reply or server error (error: %s)", c->errstr);
|
||||
}
|
||||
|
||||
if (reply->type != REDIS_REPLY_MAP) {
|
||||
fprintf(stderr, "Error: Can't send HELLO 3 command. Are you sure you're ");
|
||||
fprintf(stderr, "connected to redis-server >= 6.0.0?\nRedis error: %s\n",
|
||||
reply->type == REDIS_REPLY_ERROR ? reply->str : "(unknown)");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Enable client tracking */
|
||||
reply = redisCommand(c, "CLIENT TRACKING ON");
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
|
||||
}
|
||||
|
||||
void pushReplyHandler(void *privdata, void *r) {
|
||||
redisReply *reply = r;
|
||||
int *invalidations = privdata;
|
||||
|
||||
/* Sanity check on the invalidation reply */
|
||||
if (reply->type != REDIS_REPLY_PUSH || reply->elements != 2 ||
|
||||
reply->element[1]->type != REDIS_REPLY_ARRAY ||
|
||||
reply->element[1]->element[0]->type != REDIS_REPLY_STRING)
|
||||
{
|
||||
panicAbort("%s", "Can't parse PUSH message!");
|
||||
}
|
||||
|
||||
/* Increment our invalidation count */
|
||||
*invalidations += 1;
|
||||
|
||||
printf("pushReplyHandler(): INVALIDATE '%s' (invalidation count: %d)\n",
|
||||
reply->element[1]->element[0]->str, *invalidations);
|
||||
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* We aren't actually freeing anything here, but it is included to show that we can
|
||||
* have hiredis call our data destructor when freeing the context */
|
||||
void privdata_dtor(void *privdata) {
|
||||
unsigned int *icount = privdata;
|
||||
printf("privdata_dtor(): In context privdata dtor (invalidations: %u)\n", *icount);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j, invalidations = 0;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
|
||||
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
int port = (argc > 2) ? atoi(argv[2]) : 6379;
|
||||
|
||||
redisOptions o = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&o, hostname, port);
|
||||
|
||||
/* Set our context privdata to the address of our invalidation counter. Each
|
||||
* time our PUSH handler is called, hiredis will pass the privdata for context.
|
||||
*
|
||||
* This could also be done after we create the context like so:
|
||||
*
|
||||
* c->privdata = &invalidations;
|
||||
* c->free_privdata = privdata_dtor;
|
||||
*/
|
||||
REDIS_OPTIONS_SET_PRIVDATA(&o, &invalidations, privdata_dtor);
|
||||
|
||||
/* Set our custom PUSH message handler */
|
||||
o.push_cb = pushReplyHandler;
|
||||
|
||||
c = redisConnectWithOptions(&o);
|
||||
if (c == NULL || c->err)
|
||||
panicAbort("Connection error: %s", c ? c->errstr : "OOM");
|
||||
|
||||
/* Enable RESP3 and turn on client tracking */
|
||||
enableClientTracking(c);
|
||||
|
||||
/* Set some keys and then read them back. Once we do that, Redis will deliver
|
||||
* invalidation push messages whenever the key is modified */
|
||||
for (j = 0; j < KEY_COUNT; j++) {
|
||||
reply = redisCommand(c, "SET key:%d initial:%d", j, j);
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
|
||||
|
||||
reply = redisCommand(c, "GET key:%d", j);
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STRING);
|
||||
}
|
||||
|
||||
/* Trigger invalidation messages by updating keys we just read */
|
||||
for (j = 0; j < KEY_COUNT; j++) {
|
||||
printf(" main(): SET key:%d update:%d\n", j, j);
|
||||
reply = redisCommand(c, "SET key:%d update:%d", j, j);
|
||||
assertReplyAndFree(c, reply, REDIS_REPLY_STATUS);
|
||||
printf(" main(): SET REPLY OK\n");
|
||||
}
|
||||
|
||||
printf("\nTotal detected invalidations: %d, expected: %d\n", invalidations, KEY_COUNT);
|
||||
|
||||
/* PING server */
|
||||
redisFree(c);
|
||||
}
|
46
ext/hiredis-1.0.2/examples/example-qt.cpp
Normal file
46
ext/hiredis-1.0.2/examples/example-qt.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
|
||||
#include "example-qt.h"
|
||||
|
||||
void getCallback(redisAsyncContext *, void * r, void * privdata) {
|
||||
|
||||
redisReply * reply = static_cast<redisReply *>(r);
|
||||
ExampleQt * ex = static_cast<ExampleQt *>(privdata);
|
||||
if (reply == nullptr || ex == nullptr) return;
|
||||
|
||||
cout << "key: " << reply->str << endl;
|
||||
|
||||
ex->finish();
|
||||
}
|
||||
|
||||
void ExampleQt::run() {
|
||||
|
||||
m_ctx = redisAsyncConnect("localhost", 6379);
|
||||
|
||||
if (m_ctx->err) {
|
||||
cerr << "Error: " << m_ctx->errstr << endl;
|
||||
redisAsyncFree(m_ctx);
|
||||
emit finished();
|
||||
}
|
||||
|
||||
m_adapter.setContext(m_ctx);
|
||||
|
||||
redisAsyncCommand(m_ctx, NULL, NULL, "SET key %s", m_value);
|
||||
redisAsyncCommand(m_ctx, getCallback, this, "GET key");
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
ExampleQt example(argv[argc-1]);
|
||||
|
||||
QObject::connect(&example, SIGNAL(finished()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &example, SLOT(run()));
|
||||
|
||||
return app.exec();
|
||||
}
|
32
ext/hiredis-1.0.2/examples/example-qt.h
Normal file
32
ext/hiredis-1.0.2/examples/example-qt.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __HIREDIS_EXAMPLE_QT_H
|
||||
#define __HIREDIS_EXAMPLE_QT_H
|
||||
|
||||
#include <adapters/qt.h>
|
||||
|
||||
class ExampleQt : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExampleQt(const char * value, QObject * parent = 0)
|
||||
: QObject(parent), m_value(value) {}
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
public slots:
|
||||
void run();
|
||||
|
||||
private:
|
||||
void finish() { emit finished(); }
|
||||
|
||||
private:
|
||||
const char * m_value;
|
||||
redisAsyncContext * m_ctx;
|
||||
RedisQtAdapter m_adapter;
|
||||
|
||||
friend
|
||||
void getCallback(redisAsyncContext *, void *, void *);
|
||||
};
|
||||
|
||||
#endif /* !__HIREDIS_EXAMPLE_QT_H */
|
110
ext/hiredis-1.0.2/examples/example-ssl.c
Normal file
110
ext/hiredis-1.0.2/examples/example-ssl.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#include <hiredis_ssl.h>
|
||||
#include <win32.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j;
|
||||
redisSSLContext *ssl;
|
||||
redisSSLContextError ssl_error;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s <host> <port> <cert> <key> [ca]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
int port = atoi(argv[2]);
|
||||
const char *cert = argv[3];
|
||||
const char *key = argv[4];
|
||||
const char *ca = argc > 4 ? argv[5] : NULL;
|
||||
|
||||
redisInitOpenSSL();
|
||||
ssl = redisCreateSSLContext(ca, NULL, cert, key, NULL, &ssl_error);
|
||||
if (!ssl) {
|
||||
printf("SSL Context error: %s\n",
|
||||
redisSSLContextGetError(ssl_error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct timeval tv = { 1, 500000 }; // 1.5 seconds
|
||||
redisOptions options = {0};
|
||||
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
|
||||
options.connect_timeout = &tv;
|
||||
c = redisConnectWithOptions(&options);
|
||||
|
||||
if (c == NULL || c->err) {
|
||||
if (c) {
|
||||
printf("Connection error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
} else {
|
||||
printf("Connection error: can't allocate redis context\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
|
||||
printf("Couldn't initialize SSL!\n");
|
||||
printf("Error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* PING server */
|
||||
reply = redisCommand(c,"PING");
|
||||
printf("PING: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Set a key */
|
||||
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
|
||||
printf("SET: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Set a key using binary safe API */
|
||||
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
|
||||
printf("SET (binary API): %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Try a GET and two INCR */
|
||||
reply = redisCommand(c,"GET foo");
|
||||
printf("GET foo: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
reply = redisCommand(c,"INCR counter");
|
||||
printf("INCR counter: %lld\n", reply->integer);
|
||||
freeReplyObject(reply);
|
||||
/* again ... */
|
||||
reply = redisCommand(c,"INCR counter");
|
||||
printf("INCR counter: %lld\n", reply->integer);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Create a list of numbers, from 0 to 9 */
|
||||
reply = redisCommand(c,"DEL mylist");
|
||||
freeReplyObject(reply);
|
||||
for (j = 0; j < 10; j++) {
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf,64,"%u",j);
|
||||
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Let's check what we have inside the list */
|
||||
reply = redisCommand(c,"LRANGE mylist 0 -1");
|
||||
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||
for (j = 0; j < reply->elements; j++) {
|
||||
printf("%u) %s\n", j, reply->element[j]->str);
|
||||
}
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Disconnects and frees the context */
|
||||
redisFree(c);
|
||||
|
||||
redisFreeSSLContext(ssl);
|
||||
|
||||
return 0;
|
||||
}
|
91
ext/hiredis-1.0.2/examples/example.c
Normal file
91
ext/hiredis-1.0.2/examples/example.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <hiredis.h>
|
||||
#include <win32.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int j, isunix = 0;
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
|
||||
|
||||
if (argc > 2) {
|
||||
if (*argv[2] == 'u' || *argv[2] == 'U') {
|
||||
isunix = 1;
|
||||
/* in this case, host is the path to the unix socket */
|
||||
printf("Will connect to unix socket @%s\n", hostname);
|
||||
}
|
||||
}
|
||||
|
||||
int port = (argc > 2) ? atoi(argv[2]) : 6379;
|
||||
|
||||
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
|
||||
if (isunix) {
|
||||
c = redisConnectUnixWithTimeout(hostname, timeout);
|
||||
} else {
|
||||
c = redisConnectWithTimeout(hostname, port, timeout);
|
||||
}
|
||||
if (c == NULL || c->err) {
|
||||
if (c) {
|
||||
printf("Connection error: %s\n", c->errstr);
|
||||
redisFree(c);
|
||||
} else {
|
||||
printf("Connection error: can't allocate redis context\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* PING server */
|
||||
reply = redisCommand(c,"PING");
|
||||
printf("PING: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Set a key */
|
||||
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
|
||||
printf("SET: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Set a key using binary safe API */
|
||||
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
|
||||
printf("SET (binary API): %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Try a GET and two INCR */
|
||||
reply = redisCommand(c,"GET foo");
|
||||
printf("GET foo: %s\n", reply->str);
|
||||
freeReplyObject(reply);
|
||||
|
||||
reply = redisCommand(c,"INCR counter");
|
||||
printf("INCR counter: %lld\n", reply->integer);
|
||||
freeReplyObject(reply);
|
||||
/* again ... */
|
||||
reply = redisCommand(c,"INCR counter");
|
||||
printf("INCR counter: %lld\n", reply->integer);
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Create a list of numbers, from 0 to 9 */
|
||||
reply = redisCommand(c,"DEL mylist");
|
||||
freeReplyObject(reply);
|
||||
for (j = 0; j < 10; j++) {
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf,64,"%u",j);
|
||||
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Let's check what we have inside the list */
|
||||
reply = redisCommand(c,"LRANGE mylist 0 -1");
|
||||
if (reply->type == REDIS_REPLY_ARRAY) {
|
||||
for (j = 0; j < reply->elements; j++) {
|
||||
printf("%u) %s\n", j, reply->element[j]->str);
|
||||
}
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
|
||||
/* Disconnects and frees the context */
|
||||
redisFree(c);
|
||||
|
||||
return 0;
|
||||
}
|
12
ext/hiredis-1.0.2/fmacros.h
Normal file
12
ext/hiredis-1.0.2/fmacros.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __HIREDIS_FMACRO_H
|
||||
#define __HIREDIS_FMACRO_H
|
||||
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
/* Enable TCP_KEEPALIVE */
|
||||
#define _DARWIN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#endif
|
13
ext/hiredis-1.0.2/hiredis-config.cmake.in
Normal file
13
ext/hiredis-1.0.2/hiredis-config.cmake.in
Normal file
@ -0,0 +1,13 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
|
||||
IF (NOT TARGET hiredis::hiredis)
|
||||
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake)
|
||||
ENDIF()
|
||||
|
||||
SET(hiredis_LIBRARIES hiredis::hiredis)
|
||||
SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR})
|
||||
|
||||
check_required_components(hiredis)
|
||||
|
1174
ext/hiredis-1.0.2/hiredis.c
Normal file
1174
ext/hiredis-1.0.2/hiredis.c
Normal file
File diff suppressed because it is too large
Load Diff
336
ext/hiredis-1.0.2/hiredis.h
Normal file
336
ext/hiredis-1.0.2/hiredis.h
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_H
|
||||
#define __HIREDIS_H
|
||||
#include "read.h"
|
||||
#include <stdarg.h> /* for va_list */
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#else
|
||||
struct timeval; /* forward declaration */
|
||||
typedef long long ssize_t;
|
||||
#endif
|
||||
#include <stdint.h> /* uintXX_t, etc */
|
||||
#include "sds.h" /* for sds */
|
||||
#include "alloc.h" /* for allocation wrappers */
|
||||
|
||||
#define HIREDIS_MAJOR 1
|
||||
#define HIREDIS_MINOR 0
|
||||
#define HIREDIS_PATCH 2
|
||||
#define HIREDIS_SONAME 1.0.0
|
||||
|
||||
/* Connection type can be blocking or non-blocking and is set in the
|
||||
* least significant bit of the flags field in redisContext. */
|
||||
#define REDIS_BLOCK 0x1
|
||||
|
||||
/* Connection may be disconnected before being free'd. The second bit
|
||||
* in the flags field is set when the context is connected. */
|
||||
#define REDIS_CONNECTED 0x2
|
||||
|
||||
/* The async API might try to disconnect cleanly and flush the output
|
||||
* buffer and read all subsequent replies before disconnecting.
|
||||
* This flag means no new commands can come in and the connection
|
||||
* should be terminated once all replies have been read. */
|
||||
#define REDIS_DISCONNECTING 0x4
|
||||
|
||||
/* Flag specific to the async API which means that the context should be clean
|
||||
* up as soon as possible. */
|
||||
#define REDIS_FREEING 0x8
|
||||
|
||||
/* Flag that is set when an async callback is executed. */
|
||||
#define REDIS_IN_CALLBACK 0x10
|
||||
|
||||
/* Flag that is set when the async context has one or more subscriptions. */
|
||||
#define REDIS_SUBSCRIBED 0x20
|
||||
|
||||
/* Flag that is set when monitor mode is active */
|
||||
#define REDIS_MONITORING 0x40
|
||||
|
||||
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
|
||||
#define REDIS_REUSEADDR 0x80
|
||||
|
||||
/**
|
||||
* Flag that indicates the user does not want the context to
|
||||
* be automatically freed upon error
|
||||
*/
|
||||
#define REDIS_NO_AUTO_FREE 0x200
|
||||
|
||||
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
|
||||
|
||||
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
|
||||
* SO_REUSEADDR is being used. */
|
||||
#define REDIS_CONNECT_RETRIES 10
|
||||
|
||||
/* Forward declarations for structs defined elsewhere */
|
||||
struct redisAsyncContext;
|
||||
struct redisContext;
|
||||
|
||||
/* RESP3 push helpers and callback prototypes */
|
||||
#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH)
|
||||
typedef void (redisPushFn)(void *, void *);
|
||||
typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is the reply object returned by redisCommand() */
|
||||
typedef struct redisReply {
|
||||
int type; /* REDIS_REPLY_* */
|
||||
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
|
||||
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
|
||||
size_t len; /* Length of string */
|
||||
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
|
||||
REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
|
||||
char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
|
||||
terminated 3 character content type, such as "txt". */
|
||||
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
|
||||
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
|
||||
} redisReply;
|
||||
|
||||
redisReader *redisReaderCreate(void);
|
||||
|
||||
/* Function to free the reply objects hiredis returns by default. */
|
||||
void freeReplyObject(void *reply);
|
||||
|
||||
/* Functions to format a command according to the protocol. */
|
||||
int redisvFormatCommand(char **target, const char *format, va_list ap);
|
||||
int redisFormatCommand(char **target, const char *format, ...);
|
||||
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
|
||||
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
|
||||
void redisFreeCommand(char *cmd);
|
||||
void redisFreeSdsCommand(sds cmd);
|
||||
|
||||
enum redisConnectionType {
|
||||
REDIS_CONN_TCP,
|
||||
REDIS_CONN_UNIX,
|
||||
REDIS_CONN_USERFD
|
||||
};
|
||||
|
||||
struct redisSsl;
|
||||
|
||||
#define REDIS_OPT_NONBLOCK 0x01
|
||||
#define REDIS_OPT_REUSEADDR 0x02
|
||||
|
||||
/**
|
||||
* Don't automatically free the async object on a connection failure,
|
||||
* or other implicit conditions. Only free on an explicit call to disconnect() or free()
|
||||
*/
|
||||
#define REDIS_OPT_NOAUTOFREE 0x04
|
||||
|
||||
/* Don't automatically intercept and free RESP3 PUSH replies. */
|
||||
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
|
||||
|
||||
/* In Unix systems a file descriptor is a regular signed int, with -1
|
||||
* representing an invalid descriptor. In Windows it is a SOCKET
|
||||
* (32- or 64-bit unsigned integer depending on the architecture), where
|
||||
* all bits set (~0) is INVALID_SOCKET. */
|
||||
#ifndef _WIN32
|
||||
typedef int redisFD;
|
||||
#define REDIS_INVALID_FD -1
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */
|
||||
#else
|
||||
typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */
|
||||
#endif
|
||||
#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* the type of connection to use. This also indicates which
|
||||
* `endpoint` member field to use
|
||||
*/
|
||||
int type;
|
||||
/* bit field of REDIS_OPT_xxx */
|
||||
int options;
|
||||
/* timeout value for connect operation. If NULL, no timeout is used */
|
||||
const struct timeval *connect_timeout;
|
||||
/* timeout value for commands. If NULL, no timeout is used. This can be
|
||||
* updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */
|
||||
const struct timeval *command_timeout;
|
||||
union {
|
||||
/** use this field for tcp/ip connections */
|
||||
struct {
|
||||
const char *source_addr;
|
||||
const char *ip;
|
||||
int port;
|
||||
} tcp;
|
||||
/** use this field for unix domain sockets */
|
||||
const char *unix_socket;
|
||||
/**
|
||||
* use this field to have hiredis operate an already-open
|
||||
* file descriptor */
|
||||
redisFD fd;
|
||||
} endpoint;
|
||||
|
||||
/* Optional user defined data/destructor */
|
||||
void *privdata;
|
||||
void (*free_privdata)(void *);
|
||||
|
||||
/* A user defined PUSH message callback */
|
||||
redisPushFn *push_cb;
|
||||
redisAsyncPushFn *async_push_cb;
|
||||
} redisOptions;
|
||||
|
||||
/**
|
||||
* Helper macros to initialize options to their specified fields.
|
||||
*/
|
||||
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \
|
||||
(opts)->type = REDIS_CONN_TCP; \
|
||||
(opts)->endpoint.tcp.ip = ip_; \
|
||||
(opts)->endpoint.tcp.port = port_;
|
||||
|
||||
#define REDIS_OPTIONS_SET_UNIX(opts, path) \
|
||||
(opts)->type = REDIS_CONN_UNIX; \
|
||||
(opts)->endpoint.unix_socket = path;
|
||||
|
||||
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \
|
||||
(opts)->privdata = data; \
|
||||
(opts)->free_privdata = dtor; \
|
||||
|
||||
typedef struct redisContextFuncs {
|
||||
void (*free_privctx)(void *);
|
||||
void (*async_read)(struct redisAsyncContext *);
|
||||
void (*async_write)(struct redisAsyncContext *);
|
||||
ssize_t (*read)(struct redisContext *, char *, size_t);
|
||||
ssize_t (*write)(struct redisContext *);
|
||||
} redisContextFuncs;
|
||||
|
||||
/* Context for a connection to Redis */
|
||||
typedef struct redisContext {
|
||||
const redisContextFuncs *funcs; /* Function table */
|
||||
|
||||
int err; /* Error flags, 0 when there is no error */
|
||||
char errstr[128]; /* String representation of error when applicable */
|
||||
redisFD fd;
|
||||
int flags;
|
||||
char *obuf; /* Write buffer */
|
||||
redisReader *reader; /* Protocol reader */
|
||||
|
||||
enum redisConnectionType connection_type;
|
||||
struct timeval *connect_timeout;
|
||||
struct timeval *command_timeout;
|
||||
|
||||
struct {
|
||||
char *host;
|
||||
char *source_addr;
|
||||
int port;
|
||||
} tcp;
|
||||
|
||||
struct {
|
||||
char *path;
|
||||
} unix_sock;
|
||||
|
||||
/* For non-blocking connect */
|
||||
struct sockadr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Optional data and corresponding destructor users can use to provide
|
||||
* context to a given redisContext. Not used by hiredis. */
|
||||
void *privdata;
|
||||
void (*free_privdata)(void *);
|
||||
|
||||
/* Internal context pointer presently used by hiredis to manage
|
||||
* SSL connections. */
|
||||
void *privctx;
|
||||
|
||||
/* An optional RESP3 PUSH handler */
|
||||
redisPushFn *push_cb;
|
||||
} redisContext;
|
||||
|
||||
redisContext *redisConnectWithOptions(const redisOptions *options);
|
||||
redisContext *redisConnect(const char *ip, int port);
|
||||
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
|
||||
redisContext *redisConnectNonBlock(const char *ip, int port);
|
||||
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
||||
const char *source_addr);
|
||||
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
||||
const char *source_addr);
|
||||
redisContext *redisConnectUnix(const char *path);
|
||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
||||
redisContext *redisConnectUnixNonBlock(const char *path);
|
||||
redisContext *redisConnectFd(redisFD fd);
|
||||
|
||||
/**
|
||||
* Reconnect the given context using the saved information.
|
||||
*
|
||||
* This re-uses the exact same connect options as in the initial connection.
|
||||
* host, ip (or path), timeout and bind address are reused,
|
||||
* flags are used unmodified from the existing context.
|
||||
*
|
||||
* Returns REDIS_OK on successful connect or REDIS_ERR otherwise.
|
||||
*/
|
||||
int redisReconnect(redisContext *c);
|
||||
|
||||
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn);
|
||||
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
||||
int redisEnableKeepAlive(redisContext *c);
|
||||
void redisFree(redisContext *c);
|
||||
redisFD redisFreeKeepFd(redisContext *c);
|
||||
int redisBufferRead(redisContext *c);
|
||||
int redisBufferWrite(redisContext *c, int *done);
|
||||
|
||||
/* In a blocking context, this function first checks if there are unconsumed
|
||||
* replies to return and returns one if so. Otherwise, it flushes the output
|
||||
* buffer to the socket and reads until it has a reply. In a non-blocking
|
||||
* context, it will return unconsumed replies until there are no more. */
|
||||
int redisGetReply(redisContext *c, void **reply);
|
||||
int redisGetReplyFromReader(redisContext *c, void **reply);
|
||||
|
||||
/* Write a formatted command to the output buffer. Use these functions in blocking mode
|
||||
* to get a pipeline of commands. */
|
||||
int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);
|
||||
|
||||
/* Write a command to the output buffer. Use these functions in blocking mode
|
||||
* to get a pipeline of commands. */
|
||||
int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
|
||||
int redisAppendCommand(redisContext *c, const char *format, ...);
|
||||
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
/* Issue a command to Redis. In a blocking context, it is identical to calling
|
||||
* redisAppendCommand, followed by redisGetReply. The function will return
|
||||
* NULL if there was an error in performing the request, otherwise it will
|
||||
* return the reply. In a non-blocking context, it is identical to calling
|
||||
* only redisAppendCommand and will always return NULL. */
|
||||
void *redisvCommand(redisContext *c, const char *format, va_list ap);
|
||||
void *redisCommand(redisContext *c, const char *format, ...);
|
||||
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
12
ext/hiredis-1.0.2/hiredis.pc.in
Normal file
12
ext/hiredis-1.0.2/hiredis.pc.in
Normal file
@ -0,0 +1,12 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
install_libdir=@CMAKE_INSTALL_LIBDIR@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/${install_libdir}
|
||||
includedir=${prefix}/include
|
||||
pkgincludedir=${includedir}/hiredis
|
||||
|
||||
Name: hiredis
|
||||
Description: Minimalistic C client library for Redis.
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -lhiredis
|
||||
Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64
|
13
ext/hiredis-1.0.2/hiredis_ssl-config.cmake.in
Normal file
13
ext/hiredis-1.0.2/hiredis_ssl-config.cmake.in
Normal file
@ -0,0 +1,13 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
|
||||
IF (NOT TARGET hiredis::hiredis_ssl)
|
||||
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake)
|
||||
ENDIF()
|
||||
|
||||
SET(hiredis_ssl_LIBRARIES hiredis::hiredis_ssl)
|
||||
SET(hiredis_ssl_INCLUDE_DIRS ${hiredis_ssl_INCLUDEDIR})
|
||||
|
||||
check_required_components(hiredis_ssl)
|
||||
|
127
ext/hiredis-1.0.2/hiredis_ssl.h
Normal file
127
ext/hiredis-1.0.2/hiredis_ssl.h
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_SSL_H
|
||||
#define __HIREDIS_SSL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is the underlying struct for SSL in ssl.h, which is not included to
|
||||
* keep build dependencies short here.
|
||||
*/
|
||||
struct ssl_st;
|
||||
|
||||
/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly
|
||||
* calling OpenSSL.
|
||||
*/
|
||||
typedef struct redisSSLContext redisSSLContext;
|
||||
|
||||
/**
|
||||
* Initialization errors that redisCreateSSLContext() may return.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
REDIS_SSL_CTX_NONE = 0, /* No Error */
|
||||
REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */
|
||||
REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */
|
||||
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */
|
||||
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */
|
||||
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */
|
||||
} redisSSLContextError;
|
||||
|
||||
/**
|
||||
* Return the error message corresponding with the specified error code.
|
||||
*/
|
||||
|
||||
const char *redisSSLContextGetError(redisSSLContextError error);
|
||||
|
||||
/**
|
||||
* Helper function to initialize the OpenSSL library.
|
||||
*
|
||||
* OpenSSL requires one-time initialization before it can be used. Callers should
|
||||
* call this function only once, and only if OpenSSL is not directly initialized
|
||||
* elsewhere.
|
||||
*/
|
||||
int redisInitOpenSSL(void);
|
||||
|
||||
/**
|
||||
* Helper function to initialize an OpenSSL context that can be used
|
||||
* to initiate SSL connections.
|
||||
*
|
||||
* cacert_filename is an optional name of a CA certificate/bundle file to load
|
||||
* and use for validation.
|
||||
*
|
||||
* capath is an optional directory path where trusted CA certificate files are
|
||||
* stored in an OpenSSL-compatible structure.
|
||||
*
|
||||
* cert_filename and private_key_filename are optional names of a client side
|
||||
* certificate and private key files to use for authentication. They need to
|
||||
* be both specified or omitted.
|
||||
*
|
||||
* server_name is an optional and will be used as a server name indication
|
||||
* (SNI) TLS extension.
|
||||
*
|
||||
* If error is non-null, it will be populated in case the context creation fails
|
||||
* (returning a NULL).
|
||||
*/
|
||||
|
||||
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
|
||||
const char *cert_filename, const char *private_key_filename,
|
||||
const char *server_name, redisSSLContextError *error);
|
||||
|
||||
/**
|
||||
* Free a previously created OpenSSL context.
|
||||
*/
|
||||
void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx);
|
||||
|
||||
/**
|
||||
* Initiate SSL on an existing redisContext.
|
||||
*
|
||||
* This is similar to redisInitiateSSL() but does not require the caller
|
||||
* to directly interact with OpenSSL, and instead uses a redisSSLContext
|
||||
* previously created using redisCreateSSLContext().
|
||||
*/
|
||||
|
||||
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx);
|
||||
|
||||
/**
|
||||
* Initiate SSL/TLS negotiation on a provided OpenSSL SSL object.
|
||||
*/
|
||||
|
||||
int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HIREDIS_SSL_H */
|
12
ext/hiredis-1.0.2/hiredis_ssl.pc.in
Normal file
12
ext/hiredis-1.0.2/hiredis_ssl.pc.in
Normal file
@ -0,0 +1,12 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
pkgincludedir=${includedir}/hiredis
|
||||
|
||||
Name: hiredis_ssl
|
||||
Description: SSL Support for hiredis.
|
||||
Version: @PROJECT_VERSION@
|
||||
Requires: hiredis
|
||||
Libs: -L${libdir} -lhiredis_ssl
|
||||
Libs.private: -lssl -lcrypto
|
91
ext/hiredis-1.0.2/include/hiredis/alloc.h
Normal file
91
ext/hiredis-1.0.2/include/hiredis/alloc.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef HIREDIS_ALLOC_H
|
||||
#define HIREDIS_ALLOC_H
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structure pointing to our actually configured allocators */
|
||||
typedef struct hiredisAllocFuncs {
|
||||
void *(*mallocFn)(size_t);
|
||||
void *(*callocFn)(size_t,size_t);
|
||||
void *(*reallocFn)(void*,size_t);
|
||||
char *(*strdupFn)(const char*);
|
||||
void (*freeFn)(void*);
|
||||
} hiredisAllocFuncs;
|
||||
|
||||
hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha);
|
||||
void hiredisResetAllocators(void);
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/* Hiredis' configured allocator function pointer struct */
|
||||
extern hiredisAllocFuncs hiredisAllocFns;
|
||||
|
||||
static inline void *hi_malloc(size_t size) {
|
||||
return hiredisAllocFns.mallocFn(size);
|
||||
}
|
||||
|
||||
static inline void *hi_calloc(size_t nmemb, size_t size) {
|
||||
return hiredisAllocFns.callocFn(nmemb, size);
|
||||
}
|
||||
|
||||
static inline void *hi_realloc(void *ptr, size_t size) {
|
||||
return hiredisAllocFns.reallocFn(ptr, size);
|
||||
}
|
||||
|
||||
static inline char *hi_strdup(const char *str) {
|
||||
return hiredisAllocFns.strdupFn(str);
|
||||
}
|
||||
|
||||
static inline void hi_free(void *ptr) {
|
||||
hiredisAllocFns.freeFn(ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *hi_malloc(size_t size);
|
||||
void *hi_calloc(size_t nmemb, size_t size);
|
||||
void *hi_realloc(void *ptr, size_t size);
|
||||
char *hi_strdup(const char *str);
|
||||
void hi_free(void *ptr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HIREDIS_ALLOC_H */
|
147
ext/hiredis-1.0.2/include/hiredis/async.h
Normal file
147
ext/hiredis-1.0.2/include/hiredis/async.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_ASYNC_H
|
||||
#define __HIREDIS_ASYNC_H
|
||||
#include "hiredis.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
|
||||
struct dict; /* dictionary header is included in async.c */
|
||||
|
||||
/* Reply callback prototype and container */
|
||||
typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
|
||||
typedef struct redisCallback {
|
||||
struct redisCallback *next; /* simple singly linked list */
|
||||
redisCallbackFn *fn;
|
||||
int pending_subs;
|
||||
void *privdata;
|
||||
} redisCallback;
|
||||
|
||||
/* List of callbacks for either regular replies or pub/sub */
|
||||
typedef struct redisCallbackList {
|
||||
redisCallback *head, *tail;
|
||||
} redisCallbackList;
|
||||
|
||||
/* Connection callback prototypes */
|
||||
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
|
||||
typedef void(redisTimerCallback)(void *timer, void *privdata);
|
||||
|
||||
/* Context for an async connection to Redis */
|
||||
typedef struct redisAsyncContext {
|
||||
/* Hold the regular context, so it can be realloc'ed. */
|
||||
redisContext c;
|
||||
|
||||
/* Setup error flags so they can be used directly. */
|
||||
int err;
|
||||
char *errstr;
|
||||
|
||||
/* Not used by hiredis */
|
||||
void *data;
|
||||
void (*dataCleanup)(void *privdata);
|
||||
|
||||
/* Event library data and hooks */
|
||||
struct {
|
||||
void *data;
|
||||
|
||||
/* Hooks that are called when the library expects to start
|
||||
* reading/writing. These functions should be idempotent. */
|
||||
void (*addRead)(void *privdata);
|
||||
void (*delRead)(void *privdata);
|
||||
void (*addWrite)(void *privdata);
|
||||
void (*delWrite)(void *privdata);
|
||||
void (*cleanup)(void *privdata);
|
||||
void (*scheduleTimer)(void *privdata, struct timeval tv);
|
||||
} ev;
|
||||
|
||||
/* Called when either the connection is terminated due to an error or per
|
||||
* user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
|
||||
redisDisconnectCallback *onDisconnect;
|
||||
|
||||
/* Called when the first write event was received. */
|
||||
redisConnectCallback *onConnect;
|
||||
|
||||
/* Regular command callbacks */
|
||||
redisCallbackList replies;
|
||||
|
||||
/* Address used for connect() */
|
||||
struct sockaddr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Subscription callbacks */
|
||||
struct {
|
||||
redisCallbackList invalid;
|
||||
struct dict *channels;
|
||||
struct dict *patterns;
|
||||
} sub;
|
||||
|
||||
/* Any configured RESP3 PUSH handler */
|
||||
redisAsyncPushFn *push_cb;
|
||||
} redisAsyncContext;
|
||||
|
||||
/* Functions that proxy to hiredis */
|
||||
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options);
|
||||
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
|
||||
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
|
||||
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
|
||||
const char *source_addr);
|
||||
redisAsyncContext *redisAsyncConnectUnix(const char *path);
|
||||
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
|
||||
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
|
||||
|
||||
redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn);
|
||||
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
|
||||
void redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisAsyncFree(redisAsyncContext *ac);
|
||||
|
||||
/* Handle read/write events */
|
||||
void redisAsyncHandleRead(redisAsyncContext *ac);
|
||||
void redisAsyncHandleWrite(redisAsyncContext *ac);
|
||||
void redisAsyncHandleTimeout(redisAsyncContext *ac);
|
||||
void redisAsyncRead(redisAsyncContext *ac);
|
||||
void redisAsyncWrite(redisAsyncContext *ac);
|
||||
|
||||
/* Command functions for an async context. Write the command to the
|
||||
* output buffer and register the provided callback. */
|
||||
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
|
||||
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
|
||||
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
|
||||
int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
75
ext/hiredis-1.0.2/include/hiredis/async_private.h
Normal file
75
ext/hiredis-1.0.2/include/hiredis/async_private.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_ASYNC_PRIVATE_H
|
||||
#define __HIREDIS_ASYNC_PRIVATE_H
|
||||
|
||||
#define _EL_ADD_READ(ctx) \
|
||||
do { \
|
||||
refreshTimeout(ctx); \
|
||||
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
|
||||
} while (0)
|
||||
#define _EL_DEL_READ(ctx) do { \
|
||||
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_ADD_WRITE(ctx) \
|
||||
do { \
|
||||
refreshTimeout(ctx); \
|
||||
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
|
||||
} while (0)
|
||||
#define _EL_DEL_WRITE(ctx) do { \
|
||||
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
|
||||
} while(0)
|
||||
#define _EL_CLEANUP(ctx) do { \
|
||||
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
|
||||
ctx->ev.cleanup = NULL; \
|
||||
} while(0);
|
||||
|
||||
static inline void refreshTimeout(redisAsyncContext *ctx) {
|
||||
#define REDIS_TIMER_ISSET(tvp) \
|
||||
(tvp && ((tvp)->tv_sec || (tvp)->tv_usec))
|
||||
|
||||
#define REDIS_EL_TIMER(ac, tvp) \
|
||||
if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \
|
||||
(ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \
|
||||
}
|
||||
|
||||
if (ctx->c.flags & REDIS_CONNECTED) {
|
||||
REDIS_EL_TIMER(ctx, ctx->c.command_timeout);
|
||||
} else {
|
||||
REDIS_EL_TIMER(ctx, ctx->c.connect_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
void __redisAsyncDisconnect(redisAsyncContext *ac);
|
||||
void redisProcessCallbacks(redisAsyncContext *ac);
|
||||
|
||||
#endif /* __HIREDIS_ASYNC_PRIVATE_H */
|
126
ext/hiredis-1.0.2/include/hiredis/dict.h
Normal file
126
ext/hiredis-1.0.2/include/hiredis/dict.h
Normal file
@ -0,0 +1,126 @@
|
||||
/* Hash table implementation.
|
||||
*
|
||||
* This file implements in memory hash tables with insert/del/replace/find/
|
||||
* get-random-element operations. Hash tables will auto resize if needed
|
||||
* tables of power of two in size are used, collisions are handled by
|
||||
* chaining. See the source code for more information... :)
|
||||
*
|
||||
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __DICT_H
|
||||
#define __DICT_H
|
||||
|
||||
#define DICT_OK 0
|
||||
#define DICT_ERR 1
|
||||
|
||||
/* Unused arguments generate annoying warnings... */
|
||||
#define DICT_NOTUSED(V) ((void) V)
|
||||
|
||||
typedef struct dictEntry {
|
||||
void *key;
|
||||
void *val;
|
||||
struct dictEntry *next;
|
||||
} dictEntry;
|
||||
|
||||
typedef struct dictType {
|
||||
unsigned int (*hashFunction)(const void *key);
|
||||
void *(*keyDup)(void *privdata, const void *key);
|
||||
void *(*valDup)(void *privdata, const void *obj);
|
||||
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
|
||||
void (*keyDestructor)(void *privdata, void *key);
|
||||
void (*valDestructor)(void *privdata, void *obj);
|
||||
} dictType;
|
||||
|
||||
typedef struct dict {
|
||||
dictEntry **table;
|
||||
dictType *type;
|
||||
unsigned long size;
|
||||
unsigned long sizemask;
|
||||
unsigned long used;
|
||||
void *privdata;
|
||||
} dict;
|
||||
|
||||
typedef struct dictIterator {
|
||||
dict *ht;
|
||||
int index;
|
||||
dictEntry *entry, *nextEntry;
|
||||
} dictIterator;
|
||||
|
||||
/* This is the initial size of every hash table */
|
||||
#define DICT_HT_INITIAL_SIZE 4
|
||||
|
||||
/* ------------------------------- Macros ------------------------------------*/
|
||||
#define dictFreeEntryVal(ht, entry) \
|
||||
if ((ht)->type->valDestructor) \
|
||||
(ht)->type->valDestructor((ht)->privdata, (entry)->val)
|
||||
|
||||
#define dictSetHashVal(ht, entry, _val_) do { \
|
||||
if ((ht)->type->valDup) \
|
||||
entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
|
||||
else \
|
||||
entry->val = (_val_); \
|
||||
} while(0)
|
||||
|
||||
#define dictFreeEntryKey(ht, entry) \
|
||||
if ((ht)->type->keyDestructor) \
|
||||
(ht)->type->keyDestructor((ht)->privdata, (entry)->key)
|
||||
|
||||
#define dictSetHashKey(ht, entry, _key_) do { \
|
||||
if ((ht)->type->keyDup) \
|
||||
entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
|
||||
else \
|
||||
entry->key = (_key_); \
|
||||
} while(0)
|
||||
|
||||
#define dictCompareHashKeys(ht, key1, key2) \
|
||||
(((ht)->type->keyCompare) ? \
|
||||
(ht)->type->keyCompare((ht)->privdata, key1, key2) : \
|
||||
(key1) == (key2))
|
||||
|
||||
#define dictHashKey(ht, key) (ht)->type->hashFunction(key)
|
||||
|
||||
#define dictGetEntryKey(he) ((he)->key)
|
||||
#define dictGetEntryVal(he) ((he)->val)
|
||||
#define dictSlots(ht) ((ht)->size)
|
||||
#define dictSize(ht) ((ht)->used)
|
||||
|
||||
/* API */
|
||||
static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
|
||||
static dict *dictCreate(dictType *type, void *privDataPtr);
|
||||
static int dictExpand(dict *ht, unsigned long size);
|
||||
static int dictAdd(dict *ht, void *key, void *val);
|
||||
static int dictReplace(dict *ht, void *key, void *val);
|
||||
static int dictDelete(dict *ht, const void *key);
|
||||
static void dictRelease(dict *ht);
|
||||
static dictEntry * dictFind(dict *ht, const void *key);
|
||||
static dictIterator *dictGetIterator(dict *ht);
|
||||
static dictEntry *dictNext(dictIterator *iter);
|
||||
static void dictReleaseIterator(dictIterator *iter);
|
||||
|
||||
#endif /* __DICT_H */
|
12
ext/hiredis-1.0.2/include/hiredis/fmacros.h
Normal file
12
ext/hiredis-1.0.2/include/hiredis/fmacros.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef __HIREDIS_FMACRO_H
|
||||
#define __HIREDIS_FMACRO_H
|
||||
|
||||
#define _XOPEN_SOURCE 600
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
/* Enable TCP_KEEPALIVE */
|
||||
#define _DARWIN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#endif
|
336
ext/hiredis-1.0.2/include/hiredis/hiredis.h
Normal file
336
ext/hiredis-1.0.2/include/hiredis/hiredis.h
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_H
|
||||
#define __HIREDIS_H
|
||||
#include "read.h"
|
||||
#include <stdarg.h> /* for va_list */
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#else
|
||||
struct timeval; /* forward declaration */
|
||||
typedef long long ssize_t;
|
||||
#endif
|
||||
#include <stdint.h> /* uintXX_t, etc */
|
||||
#include "sds.h" /* for sds */
|
||||
#include "alloc.h" /* for allocation wrappers */
|
||||
|
||||
#define HIREDIS_MAJOR 1
|
||||
#define HIREDIS_MINOR 0
|
||||
#define HIREDIS_PATCH 2
|
||||
#define HIREDIS_SONAME 1.0.0
|
||||
|
||||
/* Connection type can be blocking or non-blocking and is set in the
|
||||
* least significant bit of the flags field in redisContext. */
|
||||
#define REDIS_BLOCK 0x1
|
||||
|
||||
/* Connection may be disconnected before being free'd. The second bit
|
||||
* in the flags field is set when the context is connected. */
|
||||
#define REDIS_CONNECTED 0x2
|
||||
|
||||
/* The async API might try to disconnect cleanly and flush the output
|
||||
* buffer and read all subsequent replies before disconnecting.
|
||||
* This flag means no new commands can come in and the connection
|
||||
* should be terminated once all replies have been read. */
|
||||
#define REDIS_DISCONNECTING 0x4
|
||||
|
||||
/* Flag specific to the async API which means that the context should be clean
|
||||
* up as soon as possible. */
|
||||
#define REDIS_FREEING 0x8
|
||||
|
||||
/* Flag that is set when an async callback is executed. */
|
||||
#define REDIS_IN_CALLBACK 0x10
|
||||
|
||||
/* Flag that is set when the async context has one or more subscriptions. */
|
||||
#define REDIS_SUBSCRIBED 0x20
|
||||
|
||||
/* Flag that is set when monitor mode is active */
|
||||
#define REDIS_MONITORING 0x40
|
||||
|
||||
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
|
||||
#define REDIS_REUSEADDR 0x80
|
||||
|
||||
/**
|
||||
* Flag that indicates the user does not want the context to
|
||||
* be automatically freed upon error
|
||||
*/
|
||||
#define REDIS_NO_AUTO_FREE 0x200
|
||||
|
||||
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
|
||||
|
||||
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
|
||||
* SO_REUSEADDR is being used. */
|
||||
#define REDIS_CONNECT_RETRIES 10
|
||||
|
||||
/* Forward declarations for structs defined elsewhere */
|
||||
struct redisAsyncContext;
|
||||
struct redisContext;
|
||||
|
||||
/* RESP3 push helpers and callback prototypes */
|
||||
#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH)
|
||||
typedef void (redisPushFn)(void *, void *);
|
||||
typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is the reply object returned by redisCommand() */
|
||||
typedef struct redisReply {
|
||||
int type; /* REDIS_REPLY_* */
|
||||
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
|
||||
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
|
||||
size_t len; /* Length of string */
|
||||
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
|
||||
REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
|
||||
char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
|
||||
terminated 3 character content type, such as "txt". */
|
||||
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
|
||||
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
|
||||
} redisReply;
|
||||
|
||||
redisReader *redisReaderCreate(void);
|
||||
|
||||
/* Function to free the reply objects hiredis returns by default. */
|
||||
void freeReplyObject(void *reply);
|
||||
|
||||
/* Functions to format a command according to the protocol. */
|
||||
int redisvFormatCommand(char **target, const char *format, va_list ap);
|
||||
int redisFormatCommand(char **target, const char *format, ...);
|
||||
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
|
||||
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
|
||||
void redisFreeCommand(char *cmd);
|
||||
void redisFreeSdsCommand(sds cmd);
|
||||
|
||||
enum redisConnectionType {
|
||||
REDIS_CONN_TCP,
|
||||
REDIS_CONN_UNIX,
|
||||
REDIS_CONN_USERFD
|
||||
};
|
||||
|
||||
struct redisSsl;
|
||||
|
||||
#define REDIS_OPT_NONBLOCK 0x01
|
||||
#define REDIS_OPT_REUSEADDR 0x02
|
||||
|
||||
/**
|
||||
* Don't automatically free the async object on a connection failure,
|
||||
* or other implicit conditions. Only free on an explicit call to disconnect() or free()
|
||||
*/
|
||||
#define REDIS_OPT_NOAUTOFREE 0x04
|
||||
|
||||
/* Don't automatically intercept and free RESP3 PUSH replies. */
|
||||
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
|
||||
|
||||
/* In Unix systems a file descriptor is a regular signed int, with -1
|
||||
* representing an invalid descriptor. In Windows it is a SOCKET
|
||||
* (32- or 64-bit unsigned integer depending on the architecture), where
|
||||
* all bits set (~0) is INVALID_SOCKET. */
|
||||
#ifndef _WIN32
|
||||
typedef int redisFD;
|
||||
#define REDIS_INVALID_FD -1
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */
|
||||
#else
|
||||
typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */
|
||||
#endif
|
||||
#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* the type of connection to use. This also indicates which
|
||||
* `endpoint` member field to use
|
||||
*/
|
||||
int type;
|
||||
/* bit field of REDIS_OPT_xxx */
|
||||
int options;
|
||||
/* timeout value for connect operation. If NULL, no timeout is used */
|
||||
const struct timeval *connect_timeout;
|
||||
/* timeout value for commands. If NULL, no timeout is used. This can be
|
||||
* updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */
|
||||
const struct timeval *command_timeout;
|
||||
union {
|
||||
/** use this field for tcp/ip connections */
|
||||
struct {
|
||||
const char *source_addr;
|
||||
const char *ip;
|
||||
int port;
|
||||
} tcp;
|
||||
/** use this field for unix domain sockets */
|
||||
const char *unix_socket;
|
||||
/**
|
||||
* use this field to have hiredis operate an already-open
|
||||
* file descriptor */
|
||||
redisFD fd;
|
||||
} endpoint;
|
||||
|
||||
/* Optional user defined data/destructor */
|
||||
void *privdata;
|
||||
void (*free_privdata)(void *);
|
||||
|
||||
/* A user defined PUSH message callback */
|
||||
redisPushFn *push_cb;
|
||||
redisAsyncPushFn *async_push_cb;
|
||||
} redisOptions;
|
||||
|
||||
/**
|
||||
* Helper macros to initialize options to their specified fields.
|
||||
*/
|
||||
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \
|
||||
(opts)->type = REDIS_CONN_TCP; \
|
||||
(opts)->endpoint.tcp.ip = ip_; \
|
||||
(opts)->endpoint.tcp.port = port_;
|
||||
|
||||
#define REDIS_OPTIONS_SET_UNIX(opts, path) \
|
||||
(opts)->type = REDIS_CONN_UNIX; \
|
||||
(opts)->endpoint.unix_socket = path;
|
||||
|
||||
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \
|
||||
(opts)->privdata = data; \
|
||||
(opts)->free_privdata = dtor; \
|
||||
|
||||
typedef struct redisContextFuncs {
|
||||
void (*free_privctx)(void *);
|
||||
void (*async_read)(struct redisAsyncContext *);
|
||||
void (*async_write)(struct redisAsyncContext *);
|
||||
ssize_t (*read)(struct redisContext *, char *, size_t);
|
||||
ssize_t (*write)(struct redisContext *);
|
||||
} redisContextFuncs;
|
||||
|
||||
/* Context for a connection to Redis */
|
||||
typedef struct redisContext {
|
||||
const redisContextFuncs *funcs; /* Function table */
|
||||
|
||||
int err; /* Error flags, 0 when there is no error */
|
||||
char errstr[128]; /* String representation of error when applicable */
|
||||
redisFD fd;
|
||||
int flags;
|
||||
char *obuf; /* Write buffer */
|
||||
redisReader *reader; /* Protocol reader */
|
||||
|
||||
enum redisConnectionType connection_type;
|
||||
struct timeval *connect_timeout;
|
||||
struct timeval *command_timeout;
|
||||
|
||||
struct {
|
||||
char *host;
|
||||
char *source_addr;
|
||||
int port;
|
||||
} tcp;
|
||||
|
||||
struct {
|
||||
char *path;
|
||||
} unix_sock;
|
||||
|
||||
/* For non-blocking connect */
|
||||
struct sockadr *saddr;
|
||||
size_t addrlen;
|
||||
|
||||
/* Optional data and corresponding destructor users can use to provide
|
||||
* context to a given redisContext. Not used by hiredis. */
|
||||
void *privdata;
|
||||
void (*free_privdata)(void *);
|
||||
|
||||
/* Internal context pointer presently used by hiredis to manage
|
||||
* SSL connections. */
|
||||
void *privctx;
|
||||
|
||||
/* An optional RESP3 PUSH handler */
|
||||
redisPushFn *push_cb;
|
||||
} redisContext;
|
||||
|
||||
redisContext *redisConnectWithOptions(const redisOptions *options);
|
||||
redisContext *redisConnect(const char *ip, int port);
|
||||
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
|
||||
redisContext *redisConnectNonBlock(const char *ip, int port);
|
||||
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
||||
const char *source_addr);
|
||||
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
||||
const char *source_addr);
|
||||
redisContext *redisConnectUnix(const char *path);
|
||||
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
||||
redisContext *redisConnectUnixNonBlock(const char *path);
|
||||
redisContext *redisConnectFd(redisFD fd);
|
||||
|
||||
/**
|
||||
* Reconnect the given context using the saved information.
|
||||
*
|
||||
* This re-uses the exact same connect options as in the initial connection.
|
||||
* host, ip (or path), timeout and bind address are reused,
|
||||
* flags are used unmodified from the existing context.
|
||||
*
|
||||
* Returns REDIS_OK on successful connect or REDIS_ERR otherwise.
|
||||
*/
|
||||
int redisReconnect(redisContext *c);
|
||||
|
||||
redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn);
|
||||
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
||||
int redisEnableKeepAlive(redisContext *c);
|
||||
void redisFree(redisContext *c);
|
||||
redisFD redisFreeKeepFd(redisContext *c);
|
||||
int redisBufferRead(redisContext *c);
|
||||
int redisBufferWrite(redisContext *c, int *done);
|
||||
|
||||
/* In a blocking context, this function first checks if there are unconsumed
|
||||
* replies to return and returns one if so. Otherwise, it flushes the output
|
||||
* buffer to the socket and reads until it has a reply. In a non-blocking
|
||||
* context, it will return unconsumed replies until there are no more. */
|
||||
int redisGetReply(redisContext *c, void **reply);
|
||||
int redisGetReplyFromReader(redisContext *c, void **reply);
|
||||
|
||||
/* Write a formatted command to the output buffer. Use these functions in blocking mode
|
||||
* to get a pipeline of commands. */
|
||||
int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);
|
||||
|
||||
/* Write a command to the output buffer. Use these functions in blocking mode
|
||||
* to get a pipeline of commands. */
|
||||
int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
|
||||
int redisAppendCommand(redisContext *c, const char *format, ...);
|
||||
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
/* Issue a command to Redis. In a blocking context, it is identical to calling
|
||||
* redisAppendCommand, followed by redisGetReply. The function will return
|
||||
* NULL if there was an error in performing the request, otherwise it will
|
||||
* return the reply. In a non-blocking context, it is identical to calling
|
||||
* only redisAppendCommand and will always return NULL. */
|
||||
void *redisvCommand(redisContext *c, const char *format, va_list ap);
|
||||
void *redisCommand(redisContext *c, const char *format, ...);
|
||||
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
127
ext/hiredis-1.0.2/include/hiredis/hiredis_ssl.h
Normal file
127
ext/hiredis-1.0.2/include/hiredis/hiredis_ssl.h
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __HIREDIS_SSL_H
|
||||
#define __HIREDIS_SSL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This is the underlying struct for SSL in ssl.h, which is not included to
|
||||
* keep build dependencies short here.
|
||||
*/
|
||||
struct ssl_st;
|
||||
|
||||
/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly
|
||||
* calling OpenSSL.
|
||||
*/
|
||||
typedef struct redisSSLContext redisSSLContext;
|
||||
|
||||
/**
|
||||
* Initialization errors that redisCreateSSLContext() may return.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
REDIS_SSL_CTX_NONE = 0, /* No Error */
|
||||
REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */
|
||||
REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */
|
||||
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */
|
||||
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */
|
||||
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */
|
||||
} redisSSLContextError;
|
||||
|
||||
/**
|
||||
* Return the error message corresponding with the specified error code.
|
||||
*/
|
||||
|
||||
const char *redisSSLContextGetError(redisSSLContextError error);
|
||||
|
||||
/**
|
||||
* Helper function to initialize the OpenSSL library.
|
||||
*
|
||||
* OpenSSL requires one-time initialization before it can be used. Callers should
|
||||
* call this function only once, and only if OpenSSL is not directly initialized
|
||||
* elsewhere.
|
||||
*/
|
||||
int redisInitOpenSSL(void);
|
||||
|
||||
/**
|
||||
* Helper function to initialize an OpenSSL context that can be used
|
||||
* to initiate SSL connections.
|
||||
*
|
||||
* cacert_filename is an optional name of a CA certificate/bundle file to load
|
||||
* and use for validation.
|
||||
*
|
||||
* capath is an optional directory path where trusted CA certificate files are
|
||||
* stored in an OpenSSL-compatible structure.
|
||||
*
|
||||
* cert_filename and private_key_filename are optional names of a client side
|
||||
* certificate and private key files to use for authentication. They need to
|
||||
* be both specified or omitted.
|
||||
*
|
||||
* server_name is an optional and will be used as a server name indication
|
||||
* (SNI) TLS extension.
|
||||
*
|
||||
* If error is non-null, it will be populated in case the context creation fails
|
||||
* (returning a NULL).
|
||||
*/
|
||||
|
||||
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
|
||||
const char *cert_filename, const char *private_key_filename,
|
||||
const char *server_name, redisSSLContextError *error);
|
||||
|
||||
/**
|
||||
* Free a previously created OpenSSL context.
|
||||
*/
|
||||
void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx);
|
||||
|
||||
/**
|
||||
* Initiate SSL on an existing redisContext.
|
||||
*
|
||||
* This is similar to redisInitiateSSL() but does not require the caller
|
||||
* to directly interact with OpenSSL, and instead uses a redisSSLContext
|
||||
* previously created using redisCreateSSLContext().
|
||||
*/
|
||||
|
||||
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx);
|
||||
|
||||
/**
|
||||
* Initiate SSL/TLS negotiation on a provided OpenSSL SSL object.
|
||||
*/
|
||||
|
||||
int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HIREDIS_SSL_H */
|
56
ext/hiredis-1.0.2/include/hiredis/net.h
Normal file
56
ext/hiredis-1.0.2/include/hiredis/net.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
||||
*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __NET_H
|
||||
#define __NET_H
|
||||
|
||||
#include "hiredis.h"
|
||||
|
||||
void redisNetClose(redisContext *c);
|
||||
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap);
|
||||
ssize_t redisNetWrite(redisContext *c);
|
||||
|
||||
int redisCheckSocketError(redisContext *c);
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
|
||||
int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
|
||||
int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout,
|
||||
const char *source_addr);
|
||||
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
|
||||
int redisKeepAlive(redisContext *c, int interval);
|
||||
int redisCheckConnectDone(redisContext *c, int *completed);
|
||||
|
||||
int redisSetTcpNoDelay(redisContext *c);
|
||||
|
||||
#endif
|
129
ext/hiredis-1.0.2/include/hiredis/read.h
Normal file
129
ext/hiredis-1.0.2/include/hiredis/read.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __HIREDIS_READ_H
|
||||
#define __HIREDIS_READ_H
|
||||
#include <stdio.h> /* for size_t */
|
||||
|
||||
#define REDIS_ERR -1
|
||||
#define REDIS_OK 0
|
||||
|
||||
/* When an error occurs, the err flag in a context is set to hold the type of
|
||||
* error that occurred. REDIS_ERR_IO means there was an I/O error and you
|
||||
* should use the "errno" variable to find out what is wrong.
|
||||
* For other values, the "errstr" field will hold a description. */
|
||||
#define REDIS_ERR_IO 1 /* Error in read or write */
|
||||
#define REDIS_ERR_EOF 3 /* End of file */
|
||||
#define REDIS_ERR_PROTOCOL 4 /* Protocol error */
|
||||
#define REDIS_ERR_OOM 5 /* Out of memory */
|
||||
#define REDIS_ERR_TIMEOUT 6 /* Timed out */
|
||||
#define REDIS_ERR_OTHER 2 /* Everything else... */
|
||||
|
||||
#define REDIS_REPLY_STRING 1
|
||||
#define REDIS_REPLY_ARRAY 2
|
||||
#define REDIS_REPLY_INTEGER 3
|
||||
#define REDIS_REPLY_NIL 4
|
||||
#define REDIS_REPLY_STATUS 5
|
||||
#define REDIS_REPLY_ERROR 6
|
||||
#define REDIS_REPLY_DOUBLE 7
|
||||
#define REDIS_REPLY_BOOL 8
|
||||
#define REDIS_REPLY_MAP 9
|
||||
#define REDIS_REPLY_SET 10
|
||||
#define REDIS_REPLY_ATTR 11
|
||||
#define REDIS_REPLY_PUSH 12
|
||||
#define REDIS_REPLY_BIGNUM 13
|
||||
#define REDIS_REPLY_VERB 14
|
||||
|
||||
/* Default max unused reader buffer. */
|
||||
#define REDIS_READER_MAX_BUF (1024*16)
|
||||
|
||||
/* Default multi-bulk element limit */
|
||||
#define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct redisReadTask {
|
||||
int type;
|
||||
long long elements; /* number of elements in multibulk container */
|
||||
int idx; /* index in parent (array) object */
|
||||
void *obj; /* holds user-generated value for a read task */
|
||||
struct redisReadTask *parent; /* parent task */
|
||||
void *privdata; /* user-settable arbitrary field */
|
||||
} redisReadTask;
|
||||
|
||||
typedef struct redisReplyObjectFunctions {
|
||||
void *(*createString)(const redisReadTask*, char*, size_t);
|
||||
void *(*createArray)(const redisReadTask*, size_t);
|
||||
void *(*createInteger)(const redisReadTask*, long long);
|
||||
void *(*createDouble)(const redisReadTask*, double, char*, size_t);
|
||||
void *(*createNil)(const redisReadTask*);
|
||||
void *(*createBool)(const redisReadTask*, int);
|
||||
void (*freeObject)(void*);
|
||||
} redisReplyObjectFunctions;
|
||||
|
||||
typedef struct redisReader {
|
||||
int err; /* Error flags, 0 when there is no error */
|
||||
char errstr[128]; /* String representation of error when applicable */
|
||||
|
||||
char *buf; /* Read buffer */
|
||||
size_t pos; /* Buffer cursor */
|
||||
size_t len; /* Buffer length */
|
||||
size_t maxbuf; /* Max length of unused buffer */
|
||||
long long maxelements; /* Max multi-bulk elements */
|
||||
|
||||
redisReadTask **task;
|
||||
int tasks;
|
||||
|
||||
int ridx; /* Index of current read task */
|
||||
void *reply; /* Temporary reply pointer */
|
||||
|
||||
redisReplyObjectFunctions *fn;
|
||||
void *privdata;
|
||||
} redisReader;
|
||||
|
||||
/* Public API for the protocol parser. */
|
||||
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn);
|
||||
void redisReaderFree(redisReader *r);
|
||||
int redisReaderFeed(redisReader *r, const char *buf, size_t len);
|
||||
int redisReaderGetReply(redisReader *r, void **reply);
|
||||
|
||||
#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p))
|
||||
#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply)
|
||||
#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
278
ext/hiredis-1.0.2/include/hiredis/sds.h
Normal file
278
ext/hiredis-1.0.2/include/hiredis/sds.h
Normal file
@ -0,0 +1,278 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SDS_H
|
||||
#define __SDS_H
|
||||
|
||||
#define SDS_MAX_PREALLOC (1024*1024)
|
||||
#ifdef _MSC_VER
|
||||
#define __attribute__(x)
|
||||
typedef long long ssize_t;
|
||||
#define SSIZE_MAX (LLONG_MAX >> 1)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef char *sds;
|
||||
|
||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
uint8_t len; /* used */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
uint16_t len; /* used */
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
uint32_t len; /* used */
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
|
||||
#define SDS_TYPE_5 0
|
||||
#define SDS_TYPE_8 1
|
||||
#define SDS_TYPE_16 2
|
||||
#define SDS_TYPE_32 3
|
||||
#define SDS_TYPE_64 4
|
||||
#define SDS_TYPE_MASK 7
|
||||
#define SDS_TYPE_BITS 3
|
||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)));
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
static inline size_t sdslen(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->len;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->len;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->len;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t sdsavail(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
return 0;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetlen(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sdsinclen(sds s, size_t inc) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len += (uint8_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len += (uint16_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len += (uint32_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += (uint64_t)inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* sdsalloc() = sdsavail() + sdslen() */
|
||||
static inline size_t sdsalloc(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->alloc;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->alloc;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->alloc;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->alloc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen);
|
||||
sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const sds s);
|
||||
void sdsfree(sds s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
sds sdscat(sds s, const char *t);
|
||||
sds sdscatsds(sds s, const sds t);
|
||||
sds sdscpylen(sds s, const char *t, size_t len);
|
||||
sds sdscpy(sds s, const char *t);
|
||||
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
||||
#ifdef __GNUC__
|
||||
sds sdscatprintf(sds s, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
sds sdscatprintf(sds s, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
sds sdscatfmt(sds s, char const *fmt, ...);
|
||||
sds sdstrim(sds s, const char *cset);
|
||||
int sdsrange(sds s, ssize_t start, ssize_t end);
|
||||
void sdsupdatelen(sds s);
|
||||
void sdsclear(sds s);
|
||||
int sdscmp(const sds s1, const sds s2);
|
||||
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
|
||||
void sdsfreesplitres(sds *tokens, int count);
|
||||
void sdstolower(sds s);
|
||||
void sdstoupper(sds s);
|
||||
sds sdsfromlonglong(long long value);
|
||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||
sds *sdssplitargs(const char *line, int *argc);
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||
sds sdsjoin(char **argv, int argc, char *sep);
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||
|
||||
/* Low level functions exposed to the user API */
|
||||
sds sdsMakeRoomFor(sds s, size_t addlen);
|
||||
void sdsIncrLen(sds s, int incr);
|
||||
sds sdsRemoveFreeSpace(sds s);
|
||||
size_t sdsAllocSize(sds s);
|
||||
void *sdsAllocPtr(sds s);
|
||||
|
||||
/* Export the allocator used by SDS to the program using SDS.
|
||||
* Sometimes the program SDS is linked to, may use a different set of
|
||||
* allocators, but may want to allocate or free things that SDS will
|
||||
* respectively free or allocate. */
|
||||
void *sds_malloc(size_t size);
|
||||
void *sds_realloc(void *ptr, size_t size);
|
||||
void sds_free(void *ptr);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int sdsTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#endif
|
44
ext/hiredis-1.0.2/include/hiredis/sdsalloc.h
Normal file
44
ext/hiredis-1.0.2/include/hiredis/sdsalloc.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* SDS allocator selection.
|
||||
*
|
||||
* This file is used in order to change the SDS allocator at compile time.
|
||||
* Just define the following defines to what you want to use. Also add
|
||||
* the include of your alternate allocator if needed (not needed in order
|
||||
* to use the default libc allocator). */
|
||||
|
||||
#include "alloc.h"
|
||||
|
||||
#define s_malloc hi_malloc
|
||||
#define s_realloc hi_realloc
|
||||
#define s_free hi_free
|
92
ext/hiredis-1.0.2/include/hiredis/sockcompat.h
Normal file
92
ext/hiredis-1.0.2/include/hiredis/sockcompat.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SOCKCOMPAT_H
|
||||
#define __SOCKCOMPAT_H
|
||||
|
||||
#ifndef _WIN32
|
||||
/* For POSIX systems we use the standard BSD socket API. */
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#else
|
||||
/* For Windows we use winsock. */
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef long long ssize_t;
|
||||
#endif
|
||||
|
||||
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
|
||||
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
|
||||
const char *win32_gai_strerror(int errcode);
|
||||
void win32_freeaddrinfo(struct addrinfo *res);
|
||||
SOCKET win32_socket(int domain, int type, int protocol);
|
||||
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp);
|
||||
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen);
|
||||
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
int win32_close(SOCKET fd);
|
||||
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags);
|
||||
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
|
||||
typedef ULONG nfds_t;
|
||||
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
|
||||
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
|
||||
#undef gai_strerror
|
||||
#define gai_strerror(errcode) win32_gai_strerror(errcode)
|
||||
#define freeaddrinfo(res) win32_freeaddrinfo(res)
|
||||
#define socket(domain, type, protocol) win32_socket(domain, type, protocol)
|
||||
#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp)
|
||||
#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen)
|
||||
#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen)
|
||||
#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen)
|
||||
#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen)
|
||||
#define close(fd) win32_close(fd)
|
||||
#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags)
|
||||
#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags)
|
||||
#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout)
|
||||
#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* __SOCKCOMPAT_H */
|
56
ext/hiredis-1.0.2/include/hiredis/win32.h
Normal file
56
ext/hiredis-1.0.2/include/hiredis/win32.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef _WIN32_HELPER_INCLUDE
|
||||
#define _WIN32_HELPER_INCLUDE
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <winsock2.h> /* for struct timeval */
|
||||
|
||||
#ifndef inline
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
#ifndef strncasecmp
|
||||
#define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
|
||||
#ifndef snprintf
|
||||
#define snprintf c99_snprintf
|
||||
|
||||
__inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
__inline int c99_snprintf(char* str, size_t size, const char* format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* _WIN32_HELPER_INCLUDE */
|
BIN
ext/hiredis-1.0.2/lib/ubuntu22.04/libhiredis.a
Normal file
BIN
ext/hiredis-1.0.2/lib/ubuntu22.04/libhiredis.a
Normal file
Binary file not shown.
612
ext/hiredis-1.0.2/net.c
Normal file
612
ext/hiredis-1.0.2/net.c
Normal file
@ -0,0 +1,612 @@
|
||||
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
||||
*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "sds.h"
|
||||
#include "sockcompat.h"
|
||||
#include "win32.h"
|
||||
|
||||
/* Defined in hiredis.c */
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
void redisNetClose(redisContext *c) {
|
||||
if (c && c->fd != REDIS_INVALID_FD) {
|
||||
close(c->fd);
|
||||
c->fd = REDIS_INVALID_FD;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
ssize_t nread = recv(c->fd, buf, bufcap, 0);
|
||||
if (nread == -1) {
|
||||
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
return 0;
|
||||
} else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) {
|
||||
/* especially in windows */
|
||||
__redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout");
|
||||
return -1;
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
} else if (nread == 0) {
|
||||
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
|
||||
return -1;
|
||||
} else {
|
||||
return nread;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t redisNetWrite(redisContext *c) {
|
||||
ssize_t nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
|
||||
if (nwritten < 0) {
|
||||
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
|
||||
/* Try again later */
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
|
||||
int errorno = errno; /* snprintf() may change errno */
|
||||
char buf[128] = { 0 };
|
||||
size_t len = 0;
|
||||
|
||||
if (prefix != NULL)
|
||||
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
||||
strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len);
|
||||
__redisSetError(c,type,buf);
|
||||
}
|
||||
|
||||
static int redisSetReuseAddr(redisContext *c) {
|
||||
int on = 1;
|
||||
if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int redisCreateSocket(redisContext *c, int type) {
|
||||
redisFD s;
|
||||
if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
c->fd = s;
|
||||
if (type == AF_INET) {
|
||||
if (redisSetReuseAddr(c) == REDIS_ERR) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int redisSetBlocking(redisContext *c, int blocking) {
|
||||
#ifndef _WIN32
|
||||
int flags;
|
||||
|
||||
/* Set the socket nonblocking.
|
||||
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
|
||||
* interrupted by a signal. */
|
||||
if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (blocking)
|
||||
flags &= ~O_NONBLOCK;
|
||||
else
|
||||
flags |= O_NONBLOCK;
|
||||
|
||||
if (fcntl(c->fd, F_SETFL, flags) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#else
|
||||
u_long mode = blocking ? 0 : 1;
|
||||
if (ioctl(c->fd, FIONBIO, &mode) == -1) {
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisKeepAlive(redisContext *c, int interval) {
|
||||
int val = 1;
|
||||
redisFD fd = c->fd;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
val = interval;
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#else
|
||||
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
val = interval/3;
|
||||
if (val == 0) val = 1;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
val = 3;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisSetTcpNoDelay(redisContext *c) {
|
||||
int yes = 1;
|
||||
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
|
||||
|
||||
static int redisContextTimeoutMsec(redisContext *c, long *result)
|
||||
{
|
||||
const struct timeval *timeout = c->connect_timeout;
|
||||
long msec = -1;
|
||||
|
||||
/* Only use timeout when not NULL. */
|
||||
if (timeout != NULL) {
|
||||
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
|
||||
*result = msec;
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000);
|
||||
|
||||
if (msec < 0 || msec > INT_MAX) {
|
||||
msec = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
*result = msec;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int redisContextWaitReady(redisContext *c, long msec) {
|
||||
struct pollfd wfd[1];
|
||||
|
||||
wfd[0].fd = c->fd;
|
||||
wfd[0].events = POLLOUT;
|
||||
|
||||
if (errno == EINPROGRESS) {
|
||||
int res;
|
||||
|
||||
if ((res = poll(wfd, 1, msec)) == -1) {
|
||||
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
} else if (res == 0) {
|
||||
errno = ETIMEDOUT;
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
|
||||
redisCheckSocketError(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
redisNetClose(c);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisCheckConnectDone(redisContext *c, int *completed) {
|
||||
int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen);
|
||||
if (rc == 0) {
|
||||
*completed = 1;
|
||||
return REDIS_OK;
|
||||
}
|
||||
switch (errno) {
|
||||
case EISCONN:
|
||||
*completed = 1;
|
||||
return REDIS_OK;
|
||||
case EALREADY:
|
||||
case EINPROGRESS:
|
||||
case EWOULDBLOCK:
|
||||
*completed = 0;
|
||||
return REDIS_OK;
|
||||
default:
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
int redisCheckSocketError(redisContext *c) {
|
||||
int err = 0, errno_saved = errno;
|
||||
socklen_t errlen = sizeof(err);
|
||||
|
||||
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
err = errno_saved;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
errno = err;
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
||||
const void *to_ptr = &tv;
|
||||
size_t to_sz = sizeof(tv);
|
||||
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) {
|
||||
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) {
|
||||
/* Same timeval struct, short circuit */
|
||||
if (c->connect_timeout == timeout)
|
||||
return REDIS_OK;
|
||||
|
||||
/* Allocate context timeval if we need to */
|
||||
if (c->connect_timeout == NULL) {
|
||||
c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout));
|
||||
if (c->connect_timeout == NULL)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout));
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) {
|
||||
/* Same timeval struct, short circuit */
|
||||
if (c->command_timeout == timeout)
|
||||
return REDIS_OK;
|
||||
|
||||
/* Allocate context timeval if we need to */
|
||||
if (c->command_timeout == NULL) {
|
||||
c->command_timeout = hi_malloc(sizeof(*c->command_timeout));
|
||||
if (c->command_timeout == NULL)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout));
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout,
|
||||
const char *source_addr) {
|
||||
redisFD s;
|
||||
int rv, n;
|
||||
char _port[6]; /* strlen("65535"); */
|
||||
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
|
||||
int blocking = (c->flags & REDIS_BLOCK);
|
||||
int reuseaddr = (c->flags & REDIS_REUSEADDR);
|
||||
int reuses = 0;
|
||||
long timeout_msec = -1;
|
||||
|
||||
servinfo = NULL;
|
||||
c->connection_type = REDIS_CONN_TCP;
|
||||
c->tcp.port = port;
|
||||
|
||||
/* We need to take possession of the passed parameters
|
||||
* to make them reusable for a reconnect.
|
||||
* We also carefully check we don't free data we already own,
|
||||
* as in the case of the reconnect method.
|
||||
*
|
||||
* This is a bit ugly, but atleast it works and doesn't leak memory.
|
||||
**/
|
||||
if (c->tcp.host != addr) {
|
||||
hi_free(c->tcp.host);
|
||||
|
||||
c->tcp.host = hi_strdup(addr);
|
||||
if (c->tcp.host == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
|
||||
goto oom;
|
||||
} else {
|
||||
hi_free(c->connect_timeout);
|
||||
c->connect_timeout = NULL;
|
||||
}
|
||||
|
||||
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
|
||||
__redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (source_addr == NULL) {
|
||||
hi_free(c->tcp.source_addr);
|
||||
c->tcp.source_addr = NULL;
|
||||
} else if (c->tcp.source_addr != source_addr) {
|
||||
hi_free(c->tcp.source_addr);
|
||||
c->tcp.source_addr = hi_strdup(source_addr);
|
||||
}
|
||||
|
||||
snprintf(_port, 6, "%d", port);
|
||||
memset(&hints,0,sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* Try with IPv6 if no IPv4 address was found. We do it in this order since
|
||||
* in a Redis client you can't afford to test if you have IPv6 connectivity
|
||||
* as this would add latency to every connect. Otherwise a more sensible
|
||||
* route could be: Use IPv6 if both addresses are available and there is IPv6
|
||||
* connectivity. */
|
||||
if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) {
|
||||
hints.ai_family = AF_INET6;
|
||||
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
|
||||
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
addrretry:
|
||||
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD)
|
||||
continue;
|
||||
|
||||
c->fd = s;
|
||||
if (redisSetBlocking(c,0) != REDIS_OK)
|
||||
goto error;
|
||||
if (c->tcp.source_addr) {
|
||||
int bound = 0;
|
||||
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
|
||||
if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) {
|
||||
char buf[128];
|
||||
snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
|
||||
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (reuseaddr) {
|
||||
n = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
|
||||
sizeof(n)) < 0) {
|
||||
freeaddrinfo(bservinfo);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
for (b = bservinfo; b != NULL; b = b->ai_next) {
|
||||
if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
|
||||
bound = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bservinfo);
|
||||
if (!bound) {
|
||||
char buf[128];
|
||||
snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno));
|
||||
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* For repeat connection */
|
||||
hi_free(c->saddr);
|
||||
c->saddr = hi_malloc(p->ai_addrlen);
|
||||
if (c->saddr == NULL)
|
||||
goto oom;
|
||||
|
||||
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
|
||||
c->addrlen = p->ai_addrlen;
|
||||
|
||||
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
|
||||
if (errno == EHOSTUNREACH) {
|
||||
redisNetClose(c);
|
||||
continue;
|
||||
} else if (errno == EINPROGRESS) {
|
||||
if (blocking) {
|
||||
goto wait_for_ready;
|
||||
}
|
||||
/* This is ok.
|
||||
* Note that even when it's in blocking mode, we unset blocking
|
||||
* for `connect()`
|
||||
*/
|
||||
} else if (errno == EADDRNOTAVAIL && reuseaddr) {
|
||||
if (++reuses >= REDIS_CONNECT_RETRIES) {
|
||||
goto error;
|
||||
} else {
|
||||
redisNetClose(c);
|
||||
goto addrretry;
|
||||
}
|
||||
} else {
|
||||
wait_for_ready:
|
||||
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
|
||||
goto error;
|
||||
if (redisSetTcpNoDelay(c) != REDIS_OK)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
||||
goto error;
|
||||
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
rv = REDIS_OK;
|
||||
goto end;
|
||||
}
|
||||
if (p == NULL) {
|
||||
char buf[128];
|
||||
snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno));
|
||||
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
oom:
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
error:
|
||||
rv = REDIS_ERR;
|
||||
end:
|
||||
if(servinfo) {
|
||||
freeaddrinfo(servinfo);
|
||||
}
|
||||
|
||||
return rv; // Need to return REDIS_OK if alright
|
||||
}
|
||||
|
||||
int redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout) {
|
||||
return _redisContextConnectTcp(c, addr, port, timeout, NULL);
|
||||
}
|
||||
|
||||
int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout,
|
||||
const char *source_addr) {
|
||||
return _redisContextConnectTcp(c, addr, port, timeout, source_addr);
|
||||
}
|
||||
|
||||
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
|
||||
#ifndef _WIN32
|
||||
int blocking = (c->flags & REDIS_BLOCK);
|
||||
struct sockaddr_un *sa;
|
||||
long timeout_msec = -1;
|
||||
|
||||
if (redisCreateSocket(c,AF_UNIX) < 0)
|
||||
return REDIS_ERR;
|
||||
if (redisSetBlocking(c,0) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
|
||||
c->connection_type = REDIS_CONN_UNIX;
|
||||
if (c->unix_sock.path != path) {
|
||||
hi_free(c->unix_sock.path);
|
||||
|
||||
c->unix_sock.path = hi_strdup(path);
|
||||
if (c->unix_sock.path == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
|
||||
goto oom;
|
||||
} else {
|
||||
hi_free(c->connect_timeout);
|
||||
c->connect_timeout = NULL;
|
||||
}
|
||||
|
||||
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Don't leak sockaddr if we're reconnecting */
|
||||
if (c->saddr) hi_free(c->saddr);
|
||||
|
||||
sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un)));
|
||||
if (sa == NULL)
|
||||
goto oom;
|
||||
|
||||
c->addrlen = sizeof(struct sockaddr_un);
|
||||
sa->sun_family = AF_UNIX;
|
||||
strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);
|
||||
if (connect(c->fd, (struct sockaddr*)sa, sizeof(*sa)) == -1) {
|
||||
if (errno == EINPROGRESS && !blocking) {
|
||||
/* This is ok. */
|
||||
} else {
|
||||
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset socket to be blocking after connect(2). */
|
||||
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
||||
return REDIS_ERR;
|
||||
|
||||
c->flags |= REDIS_CONNECTED;
|
||||
return REDIS_OK;
|
||||
#else
|
||||
/* We currently do not support Unix sockets for Windows. */
|
||||
/* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */
|
||||
errno = EPROTONOSUPPORT;
|
||||
return REDIS_ERR;
|
||||
#endif /* _WIN32 */
|
||||
oom:
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
56
ext/hiredis-1.0.2/net.h
Normal file
56
ext/hiredis-1.0.2/net.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
||||
*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
||||
* Jan-Erik Rediger <janerik at fnordig dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __NET_H
|
||||
#define __NET_H
|
||||
|
||||
#include "hiredis.h"
|
||||
|
||||
void redisNetClose(redisContext *c);
|
||||
ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap);
|
||||
ssize_t redisNetWrite(redisContext *c);
|
||||
|
||||
int redisCheckSocketError(redisContext *c);
|
||||
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
|
||||
int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
|
||||
int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
||||
const struct timeval *timeout,
|
||||
const char *source_addr);
|
||||
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
|
||||
int redisKeepAlive(redisContext *c, int interval);
|
||||
int redisCheckConnectDone(redisContext *c, int *completed);
|
||||
|
||||
int redisSetTcpNoDelay(redisContext *c);
|
||||
|
||||
#endif
|
739
ext/hiredis-1.0.2/read.c
Normal file
739
ext/hiredis-1.0.2/read.c
Normal file
@ -0,0 +1,739 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "fmacros.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "alloc.h"
|
||||
#include "read.h"
|
||||
#include "sds.h"
|
||||
#include "win32.h"
|
||||
|
||||
/* Initial size of our nested reply stack and how much we grow it when needd */
|
||||
#define REDIS_READER_STACK_SIZE 9
|
||||
|
||||
static void __redisReaderSetError(redisReader *r, int type, const char *str) {
|
||||
size_t len;
|
||||
|
||||
if (r->reply != NULL && r->fn && r->fn->freeObject) {
|
||||
r->fn->freeObject(r->reply);
|
||||
r->reply = NULL;
|
||||
}
|
||||
|
||||
/* Clear input buffer on errors. */
|
||||
sdsfree(r->buf);
|
||||
r->buf = NULL;
|
||||
r->pos = r->len = 0;
|
||||
|
||||
/* Reset task stack. */
|
||||
r->ridx = -1;
|
||||
|
||||
/* Set error. */
|
||||
r->err = type;
|
||||
len = strlen(str);
|
||||
len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
|
||||
memcpy(r->errstr,str,len);
|
||||
r->errstr[len] = '\0';
|
||||
}
|
||||
|
||||
static size_t chrtos(char *buf, size_t size, char byte) {
|
||||
size_t len = 0;
|
||||
|
||||
switch(byte) {
|
||||
case '\\':
|
||||
case '"':
|
||||
len = snprintf(buf,size,"\"\\%c\"",byte);
|
||||
break;
|
||||
case '\n': len = snprintf(buf,size,"\"\\n\""); break;
|
||||
case '\r': len = snprintf(buf,size,"\"\\r\""); break;
|
||||
case '\t': len = snprintf(buf,size,"\"\\t\""); break;
|
||||
case '\a': len = snprintf(buf,size,"\"\\a\""); break;
|
||||
case '\b': len = snprintf(buf,size,"\"\\b\""); break;
|
||||
default:
|
||||
if (isprint(byte))
|
||||
len = snprintf(buf,size,"\"%c\"",byte);
|
||||
else
|
||||
len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
|
||||
break;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
|
||||
char cbuf[8], sbuf[128];
|
||||
|
||||
chrtos(cbuf,sizeof(cbuf),byte);
|
||||
snprintf(sbuf,sizeof(sbuf),
|
||||
"Protocol error, got %s as reply type byte", cbuf);
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
|
||||
}
|
||||
|
||||
static void __redisReaderSetErrorOOM(redisReader *r) {
|
||||
__redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
|
||||
}
|
||||
|
||||
static char *readBytes(redisReader *r, unsigned int bytes) {
|
||||
char *p;
|
||||
if (r->len-r->pos >= bytes) {
|
||||
p = r->buf+r->pos;
|
||||
r->pos += bytes;
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find pointer to \r\n. */
|
||||
static char *seekNewline(char *s, size_t len) {
|
||||
int pos = 0;
|
||||
int _len = len-1;
|
||||
|
||||
/* Position should be < len-1 because the character at "pos" should be
|
||||
* followed by a \n. Note that strchr cannot be used because it doesn't
|
||||
* allow to search a limited length and the buffer that is being searched
|
||||
* might not have a trailing NULL character. */
|
||||
while (pos < _len) {
|
||||
while(pos < _len && s[pos] != '\r') pos++;
|
||||
if (pos==_len) {
|
||||
/* Not found. */
|
||||
return NULL;
|
||||
} else {
|
||||
if (s[pos+1] == '\n') {
|
||||
/* Found. */
|
||||
return s+pos;
|
||||
} else {
|
||||
/* Continue searching. */
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert a string into a long long. Returns REDIS_OK if the string could be
|
||||
* parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value
|
||||
* will be set to the parsed value when appropriate.
|
||||
*
|
||||
* Note that this function demands that the string strictly represents
|
||||
* a long long: no spaces or other characters before or after the string
|
||||
* representing the number are accepted, nor zeroes at the start if not
|
||||
* for the string "0" representing the zero number.
|
||||
*
|
||||
* Because of its strictness, it is safe to use this function to check if
|
||||
* you can convert a string into a long long, and obtain back the string
|
||||
* from the number without any loss in the string representation. */
|
||||
static int string2ll(const char *s, size_t slen, long long *value) {
|
||||
const char *p = s;
|
||||
size_t plen = 0;
|
||||
int negative = 0;
|
||||
unsigned long long v;
|
||||
|
||||
if (plen == slen)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Special case: first and only digit is 0. */
|
||||
if (slen == 1 && p[0] == '0') {
|
||||
if (value != NULL) *value = 0;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
if (p[0] == '-') {
|
||||
negative = 1;
|
||||
p++; plen++;
|
||||
|
||||
/* Abort on only a negative sign. */
|
||||
if (plen == slen)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* First digit should be 1-9, otherwise the string should just be 0. */
|
||||
if (p[0] >= '1' && p[0] <= '9') {
|
||||
v = p[0]-'0';
|
||||
p++; plen++;
|
||||
} else if (p[0] == '0' && slen == 1) {
|
||||
*value = 0;
|
||||
return REDIS_OK;
|
||||
} else {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
while (plen < slen && p[0] >= '0' && p[0] <= '9') {
|
||||
if (v > (ULLONG_MAX / 10)) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
v *= 10;
|
||||
|
||||
if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
v += p[0]-'0';
|
||||
|
||||
p++; plen++;
|
||||
}
|
||||
|
||||
/* Return if not all bytes were used. */
|
||||
if (plen < slen)
|
||||
return REDIS_ERR;
|
||||
|
||||
if (negative) {
|
||||
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
if (value != NULL) *value = -v;
|
||||
} else {
|
||||
if (v > LLONG_MAX) /* Overflow. */
|
||||
return REDIS_ERR;
|
||||
if (value != NULL) *value = v;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static char *readLine(redisReader *r, int *_len) {
|
||||
char *p, *s;
|
||||
int len;
|
||||
|
||||
p = r->buf+r->pos;
|
||||
s = seekNewline(p,(r->len-r->pos));
|
||||
if (s != NULL) {
|
||||
len = s-(r->buf+r->pos);
|
||||
r->pos += len+2; /* skip \r\n */
|
||||
if (_len) *_len = len;
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void moveToNextTask(redisReader *r) {
|
||||
redisReadTask *cur, *prv;
|
||||
while (r->ridx >= 0) {
|
||||
/* Return a.s.a.p. when the stack is now empty. */
|
||||
if (r->ridx == 0) {
|
||||
r->ridx--;
|
||||
return;
|
||||
}
|
||||
|
||||
cur = r->task[r->ridx];
|
||||
prv = r->task[r->ridx-1];
|
||||
assert(prv->type == REDIS_REPLY_ARRAY ||
|
||||
prv->type == REDIS_REPLY_MAP ||
|
||||
prv->type == REDIS_REPLY_SET ||
|
||||
prv->type == REDIS_REPLY_PUSH);
|
||||
if (cur->idx == prv->elements-1) {
|
||||
r->ridx--;
|
||||
} else {
|
||||
/* Reset the type because the next item can be anything */
|
||||
assert(cur->idx < prv->elements);
|
||||
cur->type = -1;
|
||||
cur->elements = -1;
|
||||
cur->idx++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int processLineItem(redisReader *r) {
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
void *obj;
|
||||
char *p;
|
||||
int len;
|
||||
|
||||
if ((p = readLine(r,&len)) != NULL) {
|
||||
if (cur->type == REDIS_REPLY_INTEGER) {
|
||||
if (r->fn && r->fn->createInteger) {
|
||||
long long v;
|
||||
if (string2ll(p, len, &v) == REDIS_ERR) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad integer value");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
obj = r->fn->createInteger(cur,v);
|
||||
} else {
|
||||
obj = (void*)REDIS_REPLY_INTEGER;
|
||||
}
|
||||
} else if (cur->type == REDIS_REPLY_DOUBLE) {
|
||||
if (r->fn && r->fn->createDouble) {
|
||||
char buf[326], *eptr;
|
||||
double d;
|
||||
|
||||
if ((size_t)len >= sizeof(buf)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Double value is too large");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
memcpy(buf,p,len);
|
||||
buf[len] = '\0';
|
||||
|
||||
if (strcasecmp(buf,",inf") == 0) {
|
||||
d = INFINITY; /* Positive infinite. */
|
||||
} else if (strcasecmp(buf,",-inf") == 0) {
|
||||
d = -INFINITY; /* Negative infinite. */
|
||||
} else {
|
||||
d = strtod((char*)buf,&eptr);
|
||||
if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad double value");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
obj = r->fn->createDouble(cur,d,buf,len);
|
||||
} else {
|
||||
obj = (void*)REDIS_REPLY_DOUBLE;
|
||||
}
|
||||
} else if (cur->type == REDIS_REPLY_NIL) {
|
||||
if (r->fn && r->fn->createNil)
|
||||
obj = r->fn->createNil(cur);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_NIL;
|
||||
} else if (cur->type == REDIS_REPLY_BOOL) {
|
||||
int bval = p[0] == 't' || p[0] == 'T';
|
||||
if (r->fn && r->fn->createBool)
|
||||
obj = r->fn->createBool(cur,bval);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_BOOL;
|
||||
} else {
|
||||
/* Type will be error or status. */
|
||||
if (r->fn && r->fn->createString)
|
||||
obj = r->fn->createString(cur,p,len);
|
||||
else
|
||||
obj = (void*)(size_t)(cur->type);
|
||||
}
|
||||
|
||||
if (obj == NULL) {
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Set reply if this is the root object. */
|
||||
if (r->ridx == 0) r->reply = obj;
|
||||
moveToNextTask(r);
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int processBulkItem(redisReader *r) {
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
void *obj = NULL;
|
||||
char *p, *s;
|
||||
long long len;
|
||||
unsigned long bytelen;
|
||||
int success = 0;
|
||||
|
||||
p = r->buf+r->pos;
|
||||
s = seekNewline(p,r->len-r->pos);
|
||||
if (s != NULL) {
|
||||
p = r->buf+r->pos;
|
||||
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
|
||||
|
||||
if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad bulk string length");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bulk string length out of range");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (len == -1) {
|
||||
/* The nil object can always be created. */
|
||||
if (r->fn && r->fn->createNil)
|
||||
obj = r->fn->createNil(cur);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_NIL;
|
||||
success = 1;
|
||||
} else {
|
||||
/* Only continue when the buffer contains the entire bulk item. */
|
||||
bytelen += len+2; /* include \r\n */
|
||||
if (r->pos+bytelen <= r->len) {
|
||||
if ((cur->type == REDIS_REPLY_VERB && len < 4) ||
|
||||
(cur->type == REDIS_REPLY_VERB && s[5] != ':'))
|
||||
{
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Verbatim string 4 bytes of content type are "
|
||||
"missing or incorrectly encoded.");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
if (r->fn && r->fn->createString)
|
||||
obj = r->fn->createString(cur,s+2,len);
|
||||
else
|
||||
obj = (void*)(long)cur->type;
|
||||
success = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Proceed when obj was created. */
|
||||
if (success) {
|
||||
if (obj == NULL) {
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
r->pos += bytelen;
|
||||
|
||||
/* Set reply if this is the root object. */
|
||||
if (r->ridx == 0) r->reply = obj;
|
||||
moveToNextTask(r);
|
||||
return REDIS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int redisReaderGrow(redisReader *r) {
|
||||
redisReadTask **aux;
|
||||
int newlen;
|
||||
|
||||
/* Grow our stack size */
|
||||
newlen = r->tasks + REDIS_READER_STACK_SIZE;
|
||||
aux = hi_realloc(r->task, sizeof(*r->task) * newlen);
|
||||
if (aux == NULL)
|
||||
goto oom;
|
||||
|
||||
r->task = aux;
|
||||
|
||||
/* Allocate new tasks */
|
||||
for (; r->tasks < newlen; r->tasks++) {
|
||||
r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
|
||||
if (r->task[r->tasks] == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Process the array, map and set types. */
|
||||
static int processAggregateItem(redisReader *r) {
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
void *obj;
|
||||
char *p;
|
||||
long long elements;
|
||||
int root = 0, len;
|
||||
|
||||
/* Set error for nested multi bulks with depth > 7 */
|
||||
if (r->ridx == r->tasks - 1) {
|
||||
if (redisReaderGrow(r) == REDIS_ERR)
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if ((p = readLine(r,&len)) != NULL) {
|
||||
if (string2ll(p, len, &elements) == REDIS_ERR) {
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Bad multi-bulk length");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
root = (r->ridx == 0);
|
||||
|
||||
if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX) ||
|
||||
(r->maxelements > 0 && elements > r->maxelements))
|
||||
{
|
||||
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
||||
"Multi-bulk length out of range");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
if (elements == -1) {
|
||||
if (r->fn && r->fn->createNil)
|
||||
obj = r->fn->createNil(cur);
|
||||
else
|
||||
obj = (void*)REDIS_REPLY_NIL;
|
||||
|
||||
if (obj == NULL) {
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
moveToNextTask(r);
|
||||
} else {
|
||||
if (cur->type == REDIS_REPLY_MAP) elements *= 2;
|
||||
|
||||
if (r->fn && r->fn->createArray)
|
||||
obj = r->fn->createArray(cur,elements);
|
||||
else
|
||||
obj = (void*)(long)cur->type;
|
||||
|
||||
if (obj == NULL) {
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Modify task stack when there are more than 0 elements. */
|
||||
if (elements > 0) {
|
||||
cur->elements = elements;
|
||||
cur->obj = obj;
|
||||
r->ridx++;
|
||||
r->task[r->ridx]->type = -1;
|
||||
r->task[r->ridx]->elements = -1;
|
||||
r->task[r->ridx]->idx = 0;
|
||||
r->task[r->ridx]->obj = NULL;
|
||||
r->task[r->ridx]->parent = cur;
|
||||
r->task[r->ridx]->privdata = r->privdata;
|
||||
} else {
|
||||
moveToNextTask(r);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set reply if this is the root object. */
|
||||
if (root) r->reply = obj;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int processItem(redisReader *r) {
|
||||
redisReadTask *cur = r->task[r->ridx];
|
||||
char *p;
|
||||
|
||||
/* check if we need to read type */
|
||||
if (cur->type < 0) {
|
||||
if ((p = readBytes(r,1)) != NULL) {
|
||||
switch (p[0]) {
|
||||
case '-':
|
||||
cur->type = REDIS_REPLY_ERROR;
|
||||
break;
|
||||
case '+':
|
||||
cur->type = REDIS_REPLY_STATUS;
|
||||
break;
|
||||
case ':':
|
||||
cur->type = REDIS_REPLY_INTEGER;
|
||||
break;
|
||||
case ',':
|
||||
cur->type = REDIS_REPLY_DOUBLE;
|
||||
break;
|
||||
case '_':
|
||||
cur->type = REDIS_REPLY_NIL;
|
||||
break;
|
||||
case '$':
|
||||
cur->type = REDIS_REPLY_STRING;
|
||||
break;
|
||||
case '*':
|
||||
cur->type = REDIS_REPLY_ARRAY;
|
||||
break;
|
||||
case '%':
|
||||
cur->type = REDIS_REPLY_MAP;
|
||||
break;
|
||||
case '~':
|
||||
cur->type = REDIS_REPLY_SET;
|
||||
break;
|
||||
case '#':
|
||||
cur->type = REDIS_REPLY_BOOL;
|
||||
break;
|
||||
case '=':
|
||||
cur->type = REDIS_REPLY_VERB;
|
||||
break;
|
||||
case '>':
|
||||
cur->type = REDIS_REPLY_PUSH;
|
||||
break;
|
||||
default:
|
||||
__redisReaderSetErrorProtocolByte(r,*p);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
} else {
|
||||
/* could not consume 1 byte */
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/* process typed item */
|
||||
switch(cur->type) {
|
||||
case REDIS_REPLY_ERROR:
|
||||
case REDIS_REPLY_STATUS:
|
||||
case REDIS_REPLY_INTEGER:
|
||||
case REDIS_REPLY_DOUBLE:
|
||||
case REDIS_REPLY_NIL:
|
||||
case REDIS_REPLY_BOOL:
|
||||
return processLineItem(r);
|
||||
case REDIS_REPLY_STRING:
|
||||
case REDIS_REPLY_VERB:
|
||||
return processBulkItem(r);
|
||||
case REDIS_REPLY_ARRAY:
|
||||
case REDIS_REPLY_MAP:
|
||||
case REDIS_REPLY_SET:
|
||||
case REDIS_REPLY_PUSH:
|
||||
return processAggregateItem(r);
|
||||
default:
|
||||
assert(NULL);
|
||||
return REDIS_ERR; /* Avoid warning. */
|
||||
}
|
||||
}
|
||||
|
||||
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
|
||||
redisReader *r;
|
||||
|
||||
r = hi_calloc(1,sizeof(redisReader));
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->buf = sdsempty();
|
||||
if (r->buf == NULL)
|
||||
goto oom;
|
||||
|
||||
r->task = hi_calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task));
|
||||
if (r->task == NULL)
|
||||
goto oom;
|
||||
|
||||
for (; r->tasks < REDIS_READER_STACK_SIZE; r->tasks++) {
|
||||
r->task[r->tasks] = hi_calloc(1, sizeof(**r->task));
|
||||
if (r->task[r->tasks] == NULL)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
r->fn = fn;
|
||||
r->maxbuf = REDIS_READER_MAX_BUF;
|
||||
r->maxelements = REDIS_READER_MAX_ARRAY_ELEMENTS;
|
||||
r->ridx = -1;
|
||||
|
||||
return r;
|
||||
oom:
|
||||
redisReaderFree(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void redisReaderFree(redisReader *r) {
|
||||
if (r == NULL)
|
||||
return;
|
||||
|
||||
if (r->reply != NULL && r->fn && r->fn->freeObject)
|
||||
r->fn->freeObject(r->reply);
|
||||
|
||||
if (r->task) {
|
||||
/* We know r->task[i] is allocated if i < r->tasks */
|
||||
for (int i = 0; i < r->tasks; i++) {
|
||||
hi_free(r->task[i]);
|
||||
}
|
||||
|
||||
hi_free(r->task);
|
||||
}
|
||||
|
||||
sdsfree(r->buf);
|
||||
hi_free(r);
|
||||
}
|
||||
|
||||
int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
|
||||
sds newbuf;
|
||||
|
||||
/* Return early when this reader is in an erroneous state. */
|
||||
if (r->err)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Copy the provided buffer. */
|
||||
if (buf != NULL && len >= 1) {
|
||||
/* Destroy internal buffer when it is empty and is quite large. */
|
||||
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
|
||||
sdsfree(r->buf);
|
||||
r->buf = sdsempty();
|
||||
if (r->buf == 0) goto oom;
|
||||
|
||||
r->pos = 0;
|
||||
}
|
||||
|
||||
newbuf = sdscatlen(r->buf,buf,len);
|
||||
if (newbuf == NULL) goto oom;
|
||||
|
||||
r->buf = newbuf;
|
||||
r->len = sdslen(r->buf);
|
||||
}
|
||||
|
||||
return REDIS_OK;
|
||||
oom:
|
||||
__redisReaderSetErrorOOM(r);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
int redisReaderGetReply(redisReader *r, void **reply) {
|
||||
/* Default target pointer to NULL. */
|
||||
if (reply != NULL)
|
||||
*reply = NULL;
|
||||
|
||||
/* Return early when this reader is in an erroneous state. */
|
||||
if (r->err)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* When the buffer is empty, there will never be a reply. */
|
||||
if (r->len == 0)
|
||||
return REDIS_OK;
|
||||
|
||||
/* Set first item to process when the stack is empty. */
|
||||
if (r->ridx == -1) {
|
||||
r->task[0]->type = -1;
|
||||
r->task[0]->elements = -1;
|
||||
r->task[0]->idx = -1;
|
||||
r->task[0]->obj = NULL;
|
||||
r->task[0]->parent = NULL;
|
||||
r->task[0]->privdata = r->privdata;
|
||||
r->ridx = 0;
|
||||
}
|
||||
|
||||
/* Process items in reply. */
|
||||
while (r->ridx >= 0)
|
||||
if (processItem(r) != REDIS_OK)
|
||||
break;
|
||||
|
||||
/* Return ASAP when an error occurred. */
|
||||
if (r->err)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* Discard part of the buffer when we've consumed at least 1k, to avoid
|
||||
* doing unnecessary calls to memmove() in sds.c. */
|
||||
if (r->pos >= 1024) {
|
||||
if (sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
|
||||
r->pos = 0;
|
||||
r->len = sdslen(r->buf);
|
||||
}
|
||||
|
||||
/* Emit a reply when there is one. */
|
||||
if (r->ridx == -1) {
|
||||
if (reply != NULL) {
|
||||
*reply = r->reply;
|
||||
} else if (r->reply != NULL && r->fn && r->fn->freeObject) {
|
||||
r->fn->freeObject(r->reply);
|
||||
}
|
||||
r->reply = NULL;
|
||||
}
|
||||
return REDIS_OK;
|
||||
}
|
129
ext/hiredis-1.0.2/read.h
Normal file
129
ext/hiredis-1.0.2/read.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __HIREDIS_READ_H
|
||||
#define __HIREDIS_READ_H
|
||||
#include <stdio.h> /* for size_t */
|
||||
|
||||
#define REDIS_ERR -1
|
||||
#define REDIS_OK 0
|
||||
|
||||
/* When an error occurs, the err flag in a context is set to hold the type of
|
||||
* error that occurred. REDIS_ERR_IO means there was an I/O error and you
|
||||
* should use the "errno" variable to find out what is wrong.
|
||||
* For other values, the "errstr" field will hold a description. */
|
||||
#define REDIS_ERR_IO 1 /* Error in read or write */
|
||||
#define REDIS_ERR_EOF 3 /* End of file */
|
||||
#define REDIS_ERR_PROTOCOL 4 /* Protocol error */
|
||||
#define REDIS_ERR_OOM 5 /* Out of memory */
|
||||
#define REDIS_ERR_TIMEOUT 6 /* Timed out */
|
||||
#define REDIS_ERR_OTHER 2 /* Everything else... */
|
||||
|
||||
#define REDIS_REPLY_STRING 1
|
||||
#define REDIS_REPLY_ARRAY 2
|
||||
#define REDIS_REPLY_INTEGER 3
|
||||
#define REDIS_REPLY_NIL 4
|
||||
#define REDIS_REPLY_STATUS 5
|
||||
#define REDIS_REPLY_ERROR 6
|
||||
#define REDIS_REPLY_DOUBLE 7
|
||||
#define REDIS_REPLY_BOOL 8
|
||||
#define REDIS_REPLY_MAP 9
|
||||
#define REDIS_REPLY_SET 10
|
||||
#define REDIS_REPLY_ATTR 11
|
||||
#define REDIS_REPLY_PUSH 12
|
||||
#define REDIS_REPLY_BIGNUM 13
|
||||
#define REDIS_REPLY_VERB 14
|
||||
|
||||
/* Default max unused reader buffer. */
|
||||
#define REDIS_READER_MAX_BUF (1024*16)
|
||||
|
||||
/* Default multi-bulk element limit */
|
||||
#define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct redisReadTask {
|
||||
int type;
|
||||
long long elements; /* number of elements in multibulk container */
|
||||
int idx; /* index in parent (array) object */
|
||||
void *obj; /* holds user-generated value for a read task */
|
||||
struct redisReadTask *parent; /* parent task */
|
||||
void *privdata; /* user-settable arbitrary field */
|
||||
} redisReadTask;
|
||||
|
||||
typedef struct redisReplyObjectFunctions {
|
||||
void *(*createString)(const redisReadTask*, char*, size_t);
|
||||
void *(*createArray)(const redisReadTask*, size_t);
|
||||
void *(*createInteger)(const redisReadTask*, long long);
|
||||
void *(*createDouble)(const redisReadTask*, double, char*, size_t);
|
||||
void *(*createNil)(const redisReadTask*);
|
||||
void *(*createBool)(const redisReadTask*, int);
|
||||
void (*freeObject)(void*);
|
||||
} redisReplyObjectFunctions;
|
||||
|
||||
typedef struct redisReader {
|
||||
int err; /* Error flags, 0 when there is no error */
|
||||
char errstr[128]; /* String representation of error when applicable */
|
||||
|
||||
char *buf; /* Read buffer */
|
||||
size_t pos; /* Buffer cursor */
|
||||
size_t len; /* Buffer length */
|
||||
size_t maxbuf; /* Max length of unused buffer */
|
||||
long long maxelements; /* Max multi-bulk elements */
|
||||
|
||||
redisReadTask **task;
|
||||
int tasks;
|
||||
|
||||
int ridx; /* Index of current read task */
|
||||
void *reply; /* Temporary reply pointer */
|
||||
|
||||
redisReplyObjectFunctions *fn;
|
||||
void *privdata;
|
||||
} redisReader;
|
||||
|
||||
/* Public API for the protocol parser. */
|
||||
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn);
|
||||
void redisReaderFree(redisReader *r);
|
||||
int redisReaderFeed(redisReader *r, const char *buf, size_t len);
|
||||
int redisReaderGetReply(redisReader *r, void **reply);
|
||||
|
||||
#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p))
|
||||
#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply)
|
||||
#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1289
ext/hiredis-1.0.2/sds.c
Normal file
1289
ext/hiredis-1.0.2/sds.c
Normal file
File diff suppressed because it is too large
Load Diff
278
ext/hiredis-1.0.2/sds.h
Normal file
278
ext/hiredis-1.0.2/sds.h
Normal file
@ -0,0 +1,278 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SDS_H
|
||||
#define __SDS_H
|
||||
|
||||
#define SDS_MAX_PREALLOC (1024*1024)
|
||||
#ifdef _MSC_VER
|
||||
#define __attribute__(x)
|
||||
typedef long long ssize_t;
|
||||
#define SSIZE_MAX (LLONG_MAX >> 1)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef char *sds;
|
||||
|
||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
||||
* However is here to document the layout of type 5 SDS strings. */
|
||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
||||
uint8_t len; /* used */
|
||||
uint8_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
||||
uint16_t len; /* used */
|
||||
uint16_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
||||
uint32_t len; /* used */
|
||||
uint32_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
||||
uint64_t len; /* used */
|
||||
uint64_t alloc; /* excluding the header and null terminator */
|
||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
||||
char buf[];
|
||||
};
|
||||
|
||||
#define SDS_TYPE_5 0
|
||||
#define SDS_TYPE_8 1
|
||||
#define SDS_TYPE_16 2
|
||||
#define SDS_TYPE_32 3
|
||||
#define SDS_TYPE_64 4
|
||||
#define SDS_TYPE_MASK 7
|
||||
#define SDS_TYPE_BITS 3
|
||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)));
|
||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
||||
|
||||
static inline size_t sdslen(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->len;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->len;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->len;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t sdsavail(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5: {
|
||||
return 0;
|
||||
}
|
||||
case SDS_TYPE_8: {
|
||||
SDS_HDR_VAR(8,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_16: {
|
||||
SDS_HDR_VAR(16,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_32: {
|
||||
SDS_HDR_VAR(32,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
case SDS_TYPE_64: {
|
||||
SDS_HDR_VAR(64,s);
|
||||
return sh->alloc - sh->len;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetlen(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sdsinclen(sds s, size_t inc) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
{
|
||||
unsigned char *fp = ((unsigned char*)s)-1;
|
||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
|
||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
||||
}
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->len += (uint8_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->len += (uint16_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->len += (uint32_t)inc;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->len += (uint64_t)inc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* sdsalloc() = sdsavail() + sdslen() */
|
||||
static inline size_t sdsalloc(const sds s) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
return SDS_TYPE_5_LEN(flags);
|
||||
case SDS_TYPE_8:
|
||||
return SDS_HDR(8,s)->alloc;
|
||||
case SDS_TYPE_16:
|
||||
return SDS_HDR(16,s)->alloc;
|
||||
case SDS_TYPE_32:
|
||||
return SDS_HDR(32,s)->alloc;
|
||||
case SDS_TYPE_64:
|
||||
return SDS_HDR(64,s)->alloc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
||||
unsigned char flags = s[-1];
|
||||
switch(flags&SDS_TYPE_MASK) {
|
||||
case SDS_TYPE_5:
|
||||
/* Nothing to do, this type has no total allocation info. */
|
||||
break;
|
||||
case SDS_TYPE_8:
|
||||
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_16:
|
||||
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_32:
|
||||
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
|
||||
break;
|
||||
case SDS_TYPE_64:
|
||||
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen);
|
||||
sds sdsnew(const char *init);
|
||||
sds sdsempty(void);
|
||||
sds sdsdup(const sds s);
|
||||
void sdsfree(sds s);
|
||||
sds sdsgrowzero(sds s, size_t len);
|
||||
sds sdscatlen(sds s, const void *t, size_t len);
|
||||
sds sdscat(sds s, const char *t);
|
||||
sds sdscatsds(sds s, const sds t);
|
||||
sds sdscpylen(sds s, const char *t, size_t len);
|
||||
sds sdscpy(sds s, const char *t);
|
||||
|
||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
||||
#ifdef __GNUC__
|
||||
sds sdscatprintf(sds s, const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
sds sdscatprintf(sds s, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
sds sdscatfmt(sds s, char const *fmt, ...);
|
||||
sds sdstrim(sds s, const char *cset);
|
||||
int sdsrange(sds s, ssize_t start, ssize_t end);
|
||||
void sdsupdatelen(sds s);
|
||||
void sdsclear(sds s);
|
||||
int sdscmp(const sds s1, const sds s2);
|
||||
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
|
||||
void sdsfreesplitres(sds *tokens, int count);
|
||||
void sdstolower(sds s);
|
||||
void sdstoupper(sds s);
|
||||
sds sdsfromlonglong(long long value);
|
||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
||||
sds *sdssplitargs(const char *line, int *argc);
|
||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
||||
sds sdsjoin(char **argv, int argc, char *sep);
|
||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
||||
|
||||
/* Low level functions exposed to the user API */
|
||||
sds sdsMakeRoomFor(sds s, size_t addlen);
|
||||
void sdsIncrLen(sds s, int incr);
|
||||
sds sdsRemoveFreeSpace(sds s);
|
||||
size_t sdsAllocSize(sds s);
|
||||
void *sdsAllocPtr(sds s);
|
||||
|
||||
/* Export the allocator used by SDS to the program using SDS.
|
||||
* Sometimes the program SDS is linked to, may use a different set of
|
||||
* allocators, but may want to allocate or free things that SDS will
|
||||
* respectively free or allocate. */
|
||||
void *sds_malloc(size_t size);
|
||||
void *sds_realloc(void *ptr, size_t size);
|
||||
void sds_free(void *ptr);
|
||||
|
||||
#ifdef REDIS_TEST
|
||||
int sdsTest(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#endif
|
44
ext/hiredis-1.0.2/sdsalloc.h
Normal file
44
ext/hiredis-1.0.2/sdsalloc.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* SDSLib 2.0 -- A C dynamic strings library
|
||||
*
|
||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2015, Oran Agra
|
||||
* Copyright (c) 2015, Redis Labs, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* SDS allocator selection.
|
||||
*
|
||||
* This file is used in order to change the SDS allocator at compile time.
|
||||
* Just define the following defines to what you want to use. Also add
|
||||
* the include of your alternate allocator if needed (not needed in order
|
||||
* to use the default libc allocator). */
|
||||
|
||||
#include "alloc.h"
|
||||
|
||||
#define s_malloc hi_malloc
|
||||
#define s_realloc hi_realloc
|
||||
#define s_free hi_free
|
248
ext/hiredis-1.0.2/sockcompat.c
Normal file
248
ext/hiredis-1.0.2/sockcompat.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define REDIS_SOCKCOMPAT_IMPLEMENTATION
|
||||
#include "sockcompat.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
static int _wsaErrorToErrno(int err) {
|
||||
switch (err) {
|
||||
case WSAEWOULDBLOCK:
|
||||
return EWOULDBLOCK;
|
||||
case WSAEINPROGRESS:
|
||||
return EINPROGRESS;
|
||||
case WSAEALREADY:
|
||||
return EALREADY;
|
||||
case WSAENOTSOCK:
|
||||
return ENOTSOCK;
|
||||
case WSAEDESTADDRREQ:
|
||||
return EDESTADDRREQ;
|
||||
case WSAEMSGSIZE:
|
||||
return EMSGSIZE;
|
||||
case WSAEPROTOTYPE:
|
||||
return EPROTOTYPE;
|
||||
case WSAENOPROTOOPT:
|
||||
return ENOPROTOOPT;
|
||||
case WSAEPROTONOSUPPORT:
|
||||
return EPROTONOSUPPORT;
|
||||
case WSAEOPNOTSUPP:
|
||||
return EOPNOTSUPP;
|
||||
case WSAEAFNOSUPPORT:
|
||||
return EAFNOSUPPORT;
|
||||
case WSAEADDRINUSE:
|
||||
return EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL:
|
||||
return EADDRNOTAVAIL;
|
||||
case WSAENETDOWN:
|
||||
return ENETDOWN;
|
||||
case WSAENETUNREACH:
|
||||
return ENETUNREACH;
|
||||
case WSAENETRESET:
|
||||
return ENETRESET;
|
||||
case WSAECONNABORTED:
|
||||
return ECONNABORTED;
|
||||
case WSAECONNRESET:
|
||||
return ECONNRESET;
|
||||
case WSAENOBUFS:
|
||||
return ENOBUFS;
|
||||
case WSAEISCONN:
|
||||
return EISCONN;
|
||||
case WSAENOTCONN:
|
||||
return ENOTCONN;
|
||||
case WSAETIMEDOUT:
|
||||
return ETIMEDOUT;
|
||||
case WSAECONNREFUSED:
|
||||
return ECONNREFUSED;
|
||||
case WSAELOOP:
|
||||
return ELOOP;
|
||||
case WSAENAMETOOLONG:
|
||||
return ENAMETOOLONG;
|
||||
case WSAEHOSTUNREACH:
|
||||
return EHOSTUNREACH;
|
||||
case WSAENOTEMPTY:
|
||||
return ENOTEMPTY;
|
||||
default:
|
||||
/* We just return a generic I/O error if we could not find a relevant error. */
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static void _updateErrno(int success) {
|
||||
errno = success ? 0 : _wsaErrorToErrno(WSAGetLastError());
|
||||
}
|
||||
|
||||
static int _initWinsock() {
|
||||
static int s_initialized = 0;
|
||||
if (!s_initialized) {
|
||||
static WSADATA wsadata;
|
||||
int err = WSAStartup(MAKEWORD(2,2), &wsadata);
|
||||
if (err != 0) {
|
||||
errno = _wsaErrorToErrno(err);
|
||||
return 0;
|
||||
}
|
||||
s_initialized = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
||||
/* Note: This function is likely to be called before other functions, so run init here. */
|
||||
if (!_initWinsock()) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
|
||||
switch (getaddrinfo(node, service, hints, res)) {
|
||||
case 0: return 0;
|
||||
case WSATRY_AGAIN: return EAI_AGAIN;
|
||||
case WSAEINVAL: return EAI_BADFLAGS;
|
||||
case WSAEAFNOSUPPORT: return EAI_FAMILY;
|
||||
case WSA_NOT_ENOUGH_MEMORY: return EAI_MEMORY;
|
||||
case WSAHOST_NOT_FOUND: return EAI_NONAME;
|
||||
case WSATYPE_NOT_FOUND: return EAI_SERVICE;
|
||||
case WSAESOCKTNOSUPPORT: return EAI_SOCKTYPE;
|
||||
default: return EAI_FAIL; /* Including WSANO_RECOVERY */
|
||||
}
|
||||
}
|
||||
|
||||
const char *win32_gai_strerror(int errcode) {
|
||||
switch (errcode) {
|
||||
case 0: errcode = 0; break;
|
||||
case EAI_AGAIN: errcode = WSATRY_AGAIN; break;
|
||||
case EAI_BADFLAGS: errcode = WSAEINVAL; break;
|
||||
case EAI_FAMILY: errcode = WSAEAFNOSUPPORT; break;
|
||||
case EAI_MEMORY: errcode = WSA_NOT_ENOUGH_MEMORY; break;
|
||||
case EAI_NONAME: errcode = WSAHOST_NOT_FOUND; break;
|
||||
case EAI_SERVICE: errcode = WSATYPE_NOT_FOUND; break;
|
||||
case EAI_SOCKTYPE: errcode = WSAESOCKTNOSUPPORT; break;
|
||||
default: errcode = WSANO_RECOVERY; break; /* Including EAI_FAIL */
|
||||
}
|
||||
return gai_strerror(errcode);
|
||||
}
|
||||
|
||||
void win32_freeaddrinfo(struct addrinfo *res) {
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
SOCKET win32_socket(int domain, int type, int protocol) {
|
||||
SOCKET s;
|
||||
|
||||
/* Note: This function is likely to be called before other functions, so run init here. */
|
||||
if (!_initWinsock()) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
_updateErrno((s = socket(domain, type, protocol)) != INVALID_SOCKET);
|
||||
return s;
|
||||
}
|
||||
|
||||
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp) {
|
||||
int ret = ioctlsocket(fd, (long)request, argp);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int ret = bind(sockfd, addr, addrlen);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
int ret = connect(sockfd, addr, addrlen);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
|
||||
/* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as
|
||||
* EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX
|
||||
* logic consistent. */
|
||||
if (errno == EWOULDBLOCK) {
|
||||
errno = EINPROGRESS;
|
||||
}
|
||||
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) {
|
||||
int ret = 0;
|
||||
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
|
||||
if (*optlen >= sizeof (struct timeval)) {
|
||||
struct timeval *tv = optval;
|
||||
DWORD timeout = 0;
|
||||
socklen_t dwlen = 0;
|
||||
ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen);
|
||||
tv->tv_sec = timeout / 1000;
|
||||
tv->tv_usec = (timeout * 1000) % 1000000;
|
||||
} else {
|
||||
ret = WSAEFAULT;
|
||||
}
|
||||
*optlen = sizeof (struct timeval);
|
||||
} else {
|
||||
ret = getsockopt(sockfd, level, optname, (char*)optval, optlen);
|
||||
}
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
int ret = 0;
|
||||
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
|
||||
const struct timeval *tv = optval;
|
||||
DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
|
||||
ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
|
||||
} else {
|
||||
ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen);
|
||||
}
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_close(SOCKET fd) {
|
||||
int ret = closesocket(fd);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags) {
|
||||
int ret = recv(sockfd, (char*)buf, (int)len, flags);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags) {
|
||||
int ret = send(sockfd, (const char*)buf, (int)len, flags);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
int ret = WSAPoll(fds, nfds, timeout);
|
||||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
#endif /* _WIN32 */
|
92
ext/hiredis-1.0.2/sockcompat.h
Normal file
92
ext/hiredis-1.0.2/sockcompat.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __SOCKCOMPAT_H
|
||||
#define __SOCKCOMPAT_H
|
||||
|
||||
#ifndef _WIN32
|
||||
/* For POSIX systems we use the standard BSD socket API. */
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#else
|
||||
/* For Windows we use winsock. */
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef long long ssize_t;
|
||||
#endif
|
||||
|
||||
/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
|
||||
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
|
||||
const char *win32_gai_strerror(int errcode);
|
||||
void win32_freeaddrinfo(struct addrinfo *res);
|
||||
SOCKET win32_socket(int domain, int type, int protocol);
|
||||
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp);
|
||||
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen);
|
||||
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
int win32_close(SOCKET fd);
|
||||
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags);
|
||||
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
|
||||
typedef ULONG nfds_t;
|
||||
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
|
||||
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
|
||||
#undef gai_strerror
|
||||
#define gai_strerror(errcode) win32_gai_strerror(errcode)
|
||||
#define freeaddrinfo(res) win32_freeaddrinfo(res)
|
||||
#define socket(domain, type, protocol) win32_socket(domain, type, protocol)
|
||||
#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp)
|
||||
#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen)
|
||||
#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen)
|
||||
#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen)
|
||||
#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen)
|
||||
#define close(fd) win32_close(fd)
|
||||
#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags)
|
||||
#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags)
|
||||
#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout)
|
||||
#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* __SOCKCOMPAT_H */
|
526
ext/hiredis-1.0.2/ssl.c
Normal file
526
ext/hiredis-1.0.2/ssl.c
Normal file
@ -0,0 +1,526 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
* Copyright (c) 2019, Redis Labs
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "hiredis.h"
|
||||
#include "async.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "win32.h"
|
||||
#include "async_private.h"
|
||||
#include "hiredis_ssl.h"
|
||||
|
||||
void __redisSetError(redisContext *c, int type, const char *str);
|
||||
|
||||
struct redisSSLContext {
|
||||
/* Associated OpenSSL SSL_CTX as created by redisCreateSSLContext() */
|
||||
SSL_CTX *ssl_ctx;
|
||||
|
||||
/* Requested SNI, or NULL */
|
||||
char *server_name;
|
||||
};
|
||||
|
||||
/* The SSL connection context is attached to SSL/TLS connections as a privdata. */
|
||||
typedef struct redisSSL {
|
||||
/**
|
||||
* OpenSSL SSL object.
|
||||
*/
|
||||
SSL *ssl;
|
||||
|
||||
/**
|
||||
* SSL_write() requires to be called again with the same arguments it was
|
||||
* previously called with in the event of an SSL_read/SSL_write situation
|
||||
*/
|
||||
size_t lastLen;
|
||||
|
||||
/** Whether the SSL layer requires read (possibly before a write) */
|
||||
int wantRead;
|
||||
|
||||
/**
|
||||
* Whether a write was requested prior to a read. If set, the write()
|
||||
* should resume whenever a read takes place, if possible
|
||||
*/
|
||||
int pendingWrite;
|
||||
} redisSSL;
|
||||
|
||||
/* Forward declaration */
|
||||
redisContextFuncs redisContextSSLFuncs;
|
||||
|
||||
/**
|
||||
* OpenSSL global initialization and locking handling callbacks.
|
||||
* Note that this is only required for OpenSSL < 1.1.0.
|
||||
*/
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define HIREDIS_USE_CRYPTO_LOCKS
|
||||
#endif
|
||||
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
#ifdef _WIN32
|
||||
typedef CRITICAL_SECTION sslLockType;
|
||||
static void sslLockInit(sslLockType* l) {
|
||||
InitializeCriticalSection(l);
|
||||
}
|
||||
static void sslLockAcquire(sslLockType* l) {
|
||||
EnterCriticalSection(l);
|
||||
}
|
||||
static void sslLockRelease(sslLockType* l) {
|
||||
LeaveCriticalSection(l);
|
||||
}
|
||||
#else
|
||||
typedef pthread_mutex_t sslLockType;
|
||||
static void sslLockInit(sslLockType *l) {
|
||||
pthread_mutex_init(l, NULL);
|
||||
}
|
||||
static void sslLockAcquire(sslLockType *l) {
|
||||
pthread_mutex_lock(l);
|
||||
}
|
||||
static void sslLockRelease(sslLockType *l) {
|
||||
pthread_mutex_unlock(l);
|
||||
}
|
||||
#endif
|
||||
|
||||
static sslLockType* ossl_locks;
|
||||
|
||||
static void opensslDoLock(int mode, int lkid, const char *f, int line) {
|
||||
sslLockType *l = ossl_locks + lkid;
|
||||
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
sslLockAcquire(l);
|
||||
} else {
|
||||
sslLockRelease(l);
|
||||
}
|
||||
|
||||
(void)f;
|
||||
(void)line;
|
||||
}
|
||||
|
||||
static int initOpensslLocks(void) {
|
||||
unsigned ii, nlocks;
|
||||
if (CRYPTO_get_locking_callback() != NULL) {
|
||||
/* Someone already set the callback before us. Don't destroy it! */
|
||||
return REDIS_OK;
|
||||
}
|
||||
nlocks = CRYPTO_num_locks();
|
||||
ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks);
|
||||
if (ossl_locks == NULL)
|
||||
return REDIS_ERR;
|
||||
|
||||
for (ii = 0; ii < nlocks; ii++) {
|
||||
sslLockInit(ossl_locks + ii);
|
||||
}
|
||||
CRYPTO_set_locking_callback(opensslDoLock);
|
||||
return REDIS_OK;
|
||||
}
|
||||
#endif /* HIREDIS_USE_CRYPTO_LOCKS */
|
||||
|
||||
int redisInitOpenSSL(void)
|
||||
{
|
||||
SSL_library_init();
|
||||
#ifdef HIREDIS_USE_CRYPTO_LOCKS
|
||||
initOpensslLocks();
|
||||
#endif
|
||||
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* redisSSLContext helper context destruction.
|
||||
*/
|
||||
|
||||
const char *redisSSLContextGetError(redisSSLContextError error)
|
||||
{
|
||||
switch (error) {
|
||||
case REDIS_SSL_CTX_NONE:
|
||||
return "No Error";
|
||||
case REDIS_SSL_CTX_CREATE_FAILED:
|
||||
return "Failed to create OpenSSL SSL_CTX";
|
||||
case REDIS_SSL_CTX_CERT_KEY_REQUIRED:
|
||||
return "Client cert and key must both be specified or skipped";
|
||||
case REDIS_SSL_CTX_CA_CERT_LOAD_FAILED:
|
||||
return "Failed to load CA Certificate or CA Path";
|
||||
case REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED:
|
||||
return "Failed to load client certificate";
|
||||
case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED:
|
||||
return "Failed to load private key";
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
}
|
||||
|
||||
void redisFreeSSLContext(redisSSLContext *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (ctx->server_name) {
|
||||
hi_free(ctx->server_name);
|
||||
ctx->server_name = NULL;
|
||||
}
|
||||
|
||||
if (ctx->ssl_ctx) {
|
||||
SSL_CTX_free(ctx->ssl_ctx);
|
||||
ctx->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
hi_free(ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* redisSSLContext helper context initialization.
|
||||
*/
|
||||
|
||||
redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath,
|
||||
const char *cert_filename, const char *private_key_filename,
|
||||
const char *server_name, redisSSLContextError *error)
|
||||
{
|
||||
redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext));
|
||||
if (ctx == NULL)
|
||||
goto error;
|
||||
|
||||
ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ctx->ssl_ctx) {
|
||||
if (error) *error = REDIS_SSL_CTX_CREATE_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
|
||||
|
||||
if ((cert_filename != NULL && private_key_filename == NULL) ||
|
||||
(private_key_filename != NULL && cert_filename == NULL)) {
|
||||
if (error) *error = REDIS_SSL_CTX_CERT_KEY_REQUIRED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (capath || cacert_filename) {
|
||||
if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) {
|
||||
if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (cert_filename) {
|
||||
if (!SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, cert_filename)) {
|
||||
if (error) *error = REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, private_key_filename, SSL_FILETYPE_PEM)) {
|
||||
if (error) *error = REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_name)
|
||||
ctx->server_name = hi_strdup(server_name);
|
||||
|
||||
return ctx;
|
||||
|
||||
error:
|
||||
redisFreeSSLContext(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* SSL Connection initialization.
|
||||
*/
|
||||
|
||||
|
||||
static int redisSSLConnect(redisContext *c, SSL *ssl) {
|
||||
if (c->privctx) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
redisSSL *rssl = hi_calloc(1, sizeof(redisSSL));
|
||||
if (rssl == NULL) {
|
||||
__redisSetError(c, REDIS_ERR_OOM, "Out of memory");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
c->funcs = &redisContextSSLFuncs;
|
||||
rssl->ssl = ssl;
|
||||
|
||||
SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
SSL_set_fd(rssl->ssl, c->fd);
|
||||
SSL_set_connect_state(rssl->ssl);
|
||||
|
||||
ERR_clear_error();
|
||||
int rv = SSL_connect(rssl->ssl);
|
||||
if (rv == 1) {
|
||||
c->privctx = rssl;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
rv = SSL_get_error(rssl->ssl, rv);
|
||||
if (((c->flags & REDIS_BLOCK) == 0) &&
|
||||
(rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) {
|
||||
c->privctx = rssl;
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
if (c->err == 0) {
|
||||
char err[512];
|
||||
if (rv == SSL_ERROR_SYSCALL)
|
||||
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno));
|
||||
else {
|
||||
unsigned long e = ERR_peek_last_error();
|
||||
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",
|
||||
ERR_reason_error_string(e));
|
||||
}
|
||||
__redisSetError(c, REDIS_ERR_IO, err);
|
||||
}
|
||||
|
||||
hi_free(rssl);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around redisSSLConnect() for users who manage their own context and
|
||||
* create their own SSL object.
|
||||
*/
|
||||
|
||||
int redisInitiateSSL(redisContext *c, SSL *ssl) {
|
||||
return redisSSLConnect(c, ssl);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around redisSSLConnect() for users who use redisSSLContext and don't
|
||||
* manage their own SSL objects.
|
||||
*/
|
||||
|
||||
int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
|
||||
{
|
||||
if (!c || !redis_ssl_ctx)
|
||||
return REDIS_ERR;
|
||||
|
||||
/* We want to verify that redisSSLConnect() won't fail on this, as it will
|
||||
* not own the SSL object in that case and we'll end up leaking.
|
||||
*/
|
||||
if (c->privctx)
|
||||
return REDIS_ERR;
|
||||
|
||||
SSL *ssl = SSL_new(redis_ssl_ctx->ssl_ctx);
|
||||
if (!ssl) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (redis_ssl_ctx->server_name) {
|
||||
if (!SSL_set_tlsext_host_name(ssl, redis_ssl_ctx->server_name)) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, "Failed to set server_name/SNI");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return redisSSLConnect(c, ssl);
|
||||
|
||||
error:
|
||||
if (ssl)
|
||||
SSL_free(ssl);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
static int maybeCheckWant(redisSSL *rssl, int rv) {
|
||||
/**
|
||||
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
|
||||
* and true is returned. False is returned otherwise
|
||||
*/
|
||||
if (rv == SSL_ERROR_WANT_READ) {
|
||||
rssl->wantRead = 1;
|
||||
return 1;
|
||||
} else if (rv == SSL_ERROR_WANT_WRITE) {
|
||||
rssl->pendingWrite = 1;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of redisContextFuncs for SSL connections.
|
||||
*/
|
||||
|
||||
static void redisSSLFree(void *privctx){
|
||||
redisSSL *rsc = privctx;
|
||||
|
||||
if (!rsc) return;
|
||||
if (rsc->ssl) {
|
||||
SSL_free(rsc->ssl);
|
||||
rsc->ssl = NULL;
|
||||
}
|
||||
hi_free(rsc);
|
||||
}
|
||||
|
||||
static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
|
||||
redisSSL *rssl = c->privctx;
|
||||
|
||||
int nread = SSL_read(rssl->ssl, buf, bufcap);
|
||||
if (nread > 0) {
|
||||
return nread;
|
||||
} else if (nread == 0) {
|
||||
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
|
||||
return -1;
|
||||
} else {
|
||||
int err = SSL_get_error(rssl->ssl, nread);
|
||||
if (c->flags & REDIS_BLOCK) {
|
||||
/**
|
||||
* In blocking mode, we should never end up in a situation where
|
||||
* we get an error without it being an actual error, except
|
||||
* in the case of EINTR, which can be spuriously received from
|
||||
* debuggers or whatever.
|
||||
*/
|
||||
if (errno == EINTR) {
|
||||
return 0;
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (errno == EAGAIN) {
|
||||
msg = "Resource temporarily unavailable";
|
||||
}
|
||||
__redisSetError(c, REDIS_ERR_IO, msg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We can very well get an EWOULDBLOCK/EAGAIN, however
|
||||
*/
|
||||
if (maybeCheckWant(rssl, err)) {
|
||||
return 0;
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t redisSSLWrite(redisContext *c) {
|
||||
redisSSL *rssl = c->privctx;
|
||||
|
||||
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
|
||||
int rv = SSL_write(rssl->ssl, c->obuf, len);
|
||||
|
||||
if (rv > 0) {
|
||||
rssl->lastLen = 0;
|
||||
} else if (rv < 0) {
|
||||
rssl->lastLen = len;
|
||||
|
||||
int err = SSL_get_error(rssl->ssl, rv);
|
||||
if ((c->flags & REDIS_BLOCK) == 0 && maybeCheckWant(rssl, err)) {
|
||||
return 0;
|
||||
} else {
|
||||
__redisSetError(c, REDIS_ERR_IO, NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void redisSSLAsyncRead(redisAsyncContext *ac) {
|
||||
int rv;
|
||||
redisSSL *rssl = ac->c.privctx;
|
||||
redisContext *c = &ac->c;
|
||||
|
||||
rssl->wantRead = 0;
|
||||
|
||||
if (rssl->pendingWrite) {
|
||||
int done;
|
||||
|
||||
/* This is probably just a write event */
|
||||
rssl->pendingWrite = 0;
|
||||
rv = redisBufferWrite(c, &done);
|
||||
if (rv == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
} else if (!done) {
|
||||
_EL_ADD_WRITE(ac);
|
||||
}
|
||||
}
|
||||
|
||||
rv = redisBufferRead(c);
|
||||
if (rv == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
} else {
|
||||
_EL_ADD_READ(ac);
|
||||
redisProcessCallbacks(ac);
|
||||
}
|
||||
}
|
||||
|
||||
static void redisSSLAsyncWrite(redisAsyncContext *ac) {
|
||||
int rv, done = 0;
|
||||
redisSSL *rssl = ac->c.privctx;
|
||||
redisContext *c = &ac->c;
|
||||
|
||||
rssl->pendingWrite = 0;
|
||||
rv = redisBufferWrite(c, &done);
|
||||
if (rv == REDIS_ERR) {
|
||||
__redisAsyncDisconnect(ac);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
if (rssl->wantRead) {
|
||||
/* Need to read-before-write */
|
||||
rssl->pendingWrite = 1;
|
||||
_EL_DEL_WRITE(ac);
|
||||
} else {
|
||||
/* No extra reads needed, just need to write more */
|
||||
_EL_ADD_WRITE(ac);
|
||||
}
|
||||
} else {
|
||||
/* Already done! */
|
||||
_EL_DEL_WRITE(ac);
|
||||
}
|
||||
|
||||
/* Always reschedule a read */
|
||||
_EL_ADD_READ(ac);
|
||||
}
|
||||
|
||||
redisContextFuncs redisContextSSLFuncs = {
|
||||
.free_privctx = redisSSLFree,
|
||||
.async_read = redisSSLAsyncRead,
|
||||
.async_write = redisSSLAsyncWrite,
|
||||
.read = redisSSLRead,
|
||||
.write = redisSSLWrite
|
||||
};
|
||||
|
1401
ext/hiredis-1.0.2/test.c
Normal file
1401
ext/hiredis-1.0.2/test.c
Normal file
File diff suppressed because it is too large
Load Diff
78
ext/hiredis-1.0.2/test.sh
Executable file
78
ext/hiredis-1.0.2/test.sh
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/sh -ue
|
||||
|
||||
REDIS_SERVER=${REDIS_SERVER:-redis-server}
|
||||
REDIS_PORT=${REDIS_PORT:-56379}
|
||||
REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443}
|
||||
TEST_SSL=${TEST_SSL:-0}
|
||||
SKIPS_AS_FAILS=${SKIPS_AS_FAILS-:0}
|
||||
SSL_TEST_ARGS=
|
||||
SKIPS_ARG=
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
PID_FILE=${tmpdir}/hiredis-test-redis.pid
|
||||
SOCK_FILE=${tmpdir}/hiredis-test-redis.sock
|
||||
|
||||
if [ "$TEST_SSL" = "1" ]; then
|
||||
SSL_CA_CERT=${tmpdir}/ca.crt
|
||||
SSL_CA_KEY=${tmpdir}/ca.key
|
||||
SSL_CERT=${tmpdir}/redis.crt
|
||||
SSL_KEY=${tmpdir}/redis.key
|
||||
|
||||
openssl genrsa -out ${tmpdir}/ca.key 4096
|
||||
openssl req \
|
||||
-x509 -new -nodes -sha256 \
|
||||
-key ${SSL_CA_KEY} \
|
||||
-days 3650 \
|
||||
-subj '/CN=Hiredis Test CA' \
|
||||
-out ${SSL_CA_CERT}
|
||||
openssl genrsa -out ${SSL_KEY} 2048
|
||||
openssl req \
|
||||
-new -sha256 \
|
||||
-key ${SSL_KEY} \
|
||||
-subj '/CN=Hiredis Test Cert' | \
|
||||
openssl x509 \
|
||||
-req -sha256 \
|
||||
-CA ${SSL_CA_CERT} \
|
||||
-CAkey ${SSL_CA_KEY} \
|
||||
-CAserial ${tmpdir}/ca.txt \
|
||||
-CAcreateserial \
|
||||
-days 365 \
|
||||
-out ${SSL_CERT}
|
||||
|
||||
SSL_TEST_ARGS="--ssl-host 127.0.0.1 --ssl-port ${REDIS_SSL_PORT} --ssl-ca-cert ${SSL_CA_CERT} --ssl-cert ${SSL_CERT} --ssl-key ${SSL_KEY}"
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
set +e
|
||||
kill $(cat ${PID_FILE})
|
||||
rm -rf ${tmpdir}
|
||||
}
|
||||
trap cleanup INT TERM EXIT
|
||||
|
||||
cat > ${tmpdir}/redis.conf <<EOF
|
||||
daemonize yes
|
||||
pidfile ${PID_FILE}
|
||||
port ${REDIS_PORT}
|
||||
bind 127.0.0.1
|
||||
unixsocket ${SOCK_FILE}
|
||||
EOF
|
||||
|
||||
if [ "$TEST_SSL" = "1" ]; then
|
||||
cat >> ${tmpdir}/redis.conf <<EOF
|
||||
tls-port ${REDIS_SSL_PORT}
|
||||
tls-ca-cert-file ${SSL_CA_CERT}
|
||||
tls-cert-file ${SSL_CERT}
|
||||
tls-key-file ${SSL_KEY}
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat ${tmpdir}/redis.conf
|
||||
${REDIS_SERVER} ${tmpdir}/redis.conf
|
||||
|
||||
# Wait until we detect the unix socket
|
||||
while [ ! -S "${SOCK_FILE}" ]; do sleep 1; done
|
||||
|
||||
# Treat skips as failures if directed
|
||||
[ "$SKIPS_AS_FAILS" = 1 ] && SKIPS_ARG="--skips-as-fails"
|
||||
|
||||
${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS} ${SKIPS_ARG}
|
56
ext/hiredis-1.0.2/win32.h
Normal file
56
ext/hiredis-1.0.2/win32.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef _WIN32_HELPER_INCLUDE
|
||||
#define _WIN32_HELPER_INCLUDE
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <winsock2.h> /* for struct timeval */
|
||||
|
||||
#ifndef inline
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
#ifndef strncasecmp
|
||||
#define strncasecmp strnicmp
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
|
||||
#ifndef snprintf
|
||||
#define snprintf c99_snprintf
|
||||
|
||||
__inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
__inline int c99_snprintf(char* str, size_t size, const char* format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* _WIN32_HELPER_INCLUDE */
|
60
ext/libpqxx-7.7.3/.circleci/config.yml
Normal file
60
ext/libpqxx-7.7.3/.circleci/config.yml
Normal file
@ -0,0 +1,60 @@
|
||||
# CircleCI config for automated test builds triggered from Github.
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: debian:testing
|
||||
# - image: postgres:latest
|
||||
environment:
|
||||
- PGHOST: "/tmp"
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Configure apt archives
|
||||
command: apt update
|
||||
- run:
|
||||
name: Install
|
||||
command: apt install -y lsb-release python3 cmake postgresql libpq-dev postgresql-server-dev-all build-essential autoconf dh-autoreconf autoconf-archive automake cppcheck
|
||||
- run:
|
||||
name: Identify
|
||||
command: lsb_release -a && c++ --version
|
||||
- run:
|
||||
name: Prepare postgres
|
||||
command: |
|
||||
mkdir /tmp/db &&
|
||||
chown postgres /tmp/db &&
|
||||
su postgres -c '/usr/lib/postgresql/*/bin/initdb --pgdata /tmp/db --auth trust --nosync'
|
||||
- run:
|
||||
name: Run postgres
|
||||
command: (su postgres -c '/usr/lib/postgresql/*/bin/postgres -D /tmp/db -k /tmp' &) && sleep 5
|
||||
- run:
|
||||
name: Create postgres user
|
||||
command: su postgres -c "createuser -w -d root"
|
||||
- run:
|
||||
name: Set up database
|
||||
command: createdb root
|
||||
- run:
|
||||
name: Autogen
|
||||
command: NOCONFIGURE=1 ./autogen.sh
|
||||
- run:
|
||||
name: Configure
|
||||
command: |
|
||||
./configure \
|
||||
--disable-documentation \
|
||||
--enable-maintainer-mode \
|
||||
--enable-audit \
|
||||
--enable-shared --disable-static \
|
||||
CXXFLAGS=-O3
|
||||
- store_artifacts:
|
||||
path: config.log
|
||||
- run:
|
||||
name: Make
|
||||
command: make -j$(nproc)
|
||||
- run:
|
||||
name: Test
|
||||
command: PGDATA=db/data make check
|
||||
- run:
|
||||
name: Analyse
|
||||
command: ./tools/lint --full >lint.log
|
||||
- store_artifacts:
|
||||
path: lint.log
|
71
ext/libpqxx-7.7.3/.clang-format
Normal file
71
ext/libpqxx-7.7.3/.clang-format
Normal file
@ -0,0 +1,71 @@
|
||||
Language: Cpp
|
||||
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
# AllowAllArgumentsOnNextLine: true
|
||||
# AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
# AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
# AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
# AlwaysBreakTemplateDeclarations: No
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
# AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterExternBlock: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterStruct: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyNamespace: false
|
||||
SplitEmptyRecord: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: AfterColon
|
||||
# BreakInheritanceList: AfterColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 79
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: true
|
||||
FixNamespaceComments: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
# NamespaceIndentation: All
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
# SpaceBeforeCpp11BracedList: false
|
||||
# SpaceBeforeCtorInitializerColon: true
|
||||
# SpaceBeforeInheritanceColon: true
|
||||
# SpaceBeforeParents: ControlStatements
|
||||
# SpaceBeforeRangedBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
UseTab: Never
|
||||
---
|
184
ext/libpqxx-7.7.3/.cmake-format
Normal file
184
ext/libpqxx-7.7.3/.cmake-format
Normal file
@ -0,0 +1,184 @@
|
||||
format:
|
||||
_help_max_prefix_chars:
|
||||
- !!python/unicode 'If the statement spelling length (including space and'
|
||||
- !!python/unicode 'parenthesis) is larger than the tab width by more than this'
|
||||
- !!python/unicode 'amount, then force reject un-nested layouts.'
|
||||
max_prefix_chars: 10
|
||||
_help_dangle_align:
|
||||
- !!python/unicode 'If the trailing parenthesis must be ''dangled'' on its own'
|
||||
- !!python/unicode 'line, then align it to this reference: `prefix`: the start'
|
||||
- !!python/unicode 'of the statement, `prefix-indent`: the start of the'
|
||||
- !!python/unicode 'statement, plus one indentation level, `child`: align to'
|
||||
- !!python/unicode 'the column of the arguments'
|
||||
dangle_align: !!python/unicode 'prefix'
|
||||
_help_max_subgroups_hwrap:
|
||||
- !!python/unicode 'If an argument group contains more than this many sub-groups'
|
||||
- !!python/unicode '(parg or kwarg groups) then force it to a vertical layout.'
|
||||
max_subgroups_hwrap: 2
|
||||
_help_min_prefix_chars:
|
||||
- !!python/unicode 'If the statement spelling length (including space and'
|
||||
- !!python/unicode 'parenthesis) is smaller than this amount, then force reject'
|
||||
- !!python/unicode 'nested layouts.'
|
||||
min_prefix_chars: 4
|
||||
_help_max_pargs_hwrap:
|
||||
- !!python/unicode 'If a positional argument group contains more than this many'
|
||||
- !!python/unicode 'arguments, then force it to a vertical layout.'
|
||||
max_pargs_hwrap: 6
|
||||
_help_max_lines_hwrap:
|
||||
- !!python/unicode 'If a candidate layout is wrapped horizontally but it exceeds'
|
||||
- !!python/unicode 'this many lines, then reject the layout.'
|
||||
max_lines_hwrap: 2
|
||||
_help_autosort:
|
||||
- !!python/unicode 'If true, the parsers may infer whether or not an argument'
|
||||
- !!python/unicode 'list is sortable (without annotation).'
|
||||
autosort: false
|
||||
_help_line_ending:
|
||||
- !!python/unicode 'What style line endings to use in the output.'
|
||||
line_ending: !!python/unicode 'unix'
|
||||
_help_line_width:
|
||||
- !!python/unicode 'How wide to allow formatted cmake files'
|
||||
line_width: 80
|
||||
_help_dangle_parens:
|
||||
- !!python/unicode 'If a statement is wrapped to more than one line, then dangle'
|
||||
- !!python/unicode 'the closing parenthesis on its own line.'
|
||||
dangle_parens: true
|
||||
_help_tab_size:
|
||||
- !!python/unicode 'How many spaces to tab for indent'
|
||||
tab_size: 4
|
||||
_help_always_wrap:
|
||||
- !!python/unicode 'A list of command names which should always be wrapped'
|
||||
always_wrap: []
|
||||
_help_require_valid_layout:
|
||||
- !!python/unicode 'By default, if cmake-format cannot successfully fit'
|
||||
- !!python/unicode 'everything into the desired linewidth it will apply the'
|
||||
- !!python/unicode 'last, most agressive attempt that it made. If this flag is'
|
||||
- !!python/unicode 'True, however, cmake-format will print error, exit with non-'
|
||||
- !!python/unicode 'zero status code, and write-out nothing'
|
||||
require_valid_layout: true
|
||||
_help_keyword_case:
|
||||
- !!python/unicode 'Format keywords consistently as ''lower'' or ''upper'' case'
|
||||
keyword_case: !!python/unicode 'unchanged'
|
||||
_help_layout_passes:
|
||||
- !!python/unicode 'A dictionary mapping layout nodes to a list of wrap'
|
||||
- !!python/unicode 'decisions. See the documentation for more information.'
|
||||
layout_passes: {}
|
||||
_help_enable_sort:
|
||||
- !!python/unicode 'If true, the argument lists which are known to be sortable'
|
||||
- !!python/unicode 'will be sorted lexicographically'
|
||||
enable_sort: true
|
||||
_help_markup: !!python/unicode 'Options affecting comment reflow and formatting.'
|
||||
markup:
|
||||
_help_literal_comment_pattern:
|
||||
- !!python/unicode 'If comment markup is enabled, don''t reflow any comment block'
|
||||
- !!python/unicode 'which matches this (regex) pattern. Default is `None`'
|
||||
- !!python/unicode '(disabled).'
|
||||
literal_comment_pattern: null
|
||||
_help_hashruler_min_length:
|
||||
- !!python/unicode 'If a comment line starts with at least this many consecutive'
|
||||
- !!python/unicode 'hash characters, then don''t lstrip() them off. This allows'
|
||||
- !!python/unicode 'for lazy hash rulers where the first hash char is not'
|
||||
- !!python/unicode 'separated by space'
|
||||
hashruler_min_length: 10
|
||||
_help_fence_pattern:
|
||||
- !!python/unicode 'Regular expression to match preformat fences in comments'
|
||||
- !!python/unicode 'default=r''^\s*([`~]{3}[`~]*)(.*)$'''
|
||||
fence_pattern: !!python/unicode '^\s*([`~]{3}[`~]*)(.*)$'
|
||||
_help_canonicalize_hashrulers:
|
||||
- !!python/unicode 'If true, then insert a space between the first hash char and'
|
||||
- !!python/unicode 'remaining hash chars in a hash ruler, and normalize its'
|
||||
- !!python/unicode 'length to fill the column'
|
||||
canonicalize_hashrulers: true
|
||||
_help_explicit_trailing_pattern:
|
||||
- !!python/unicode 'If a comment line matches starts with this pattern then it'
|
||||
- !!python/unicode 'is explicitly a trailing comment for the preceeding'
|
||||
- !!python/unicode 'argument. Default is ''#<'''
|
||||
explicit_trailing_pattern: !!python/unicode '#<'
|
||||
_help_first_comment_is_literal:
|
||||
- !!python/unicode 'If comment markup is enabled, don''t reflow the first comment'
|
||||
- !!python/unicode 'block in each listfile. Use this to preserve formatting of'
|
||||
- !!python/unicode 'your copyright/license statements.'
|
||||
first_comment_is_literal: false
|
||||
_help_enable_markup:
|
||||
- !!python/unicode 'enable comment markup parsing and reflow'
|
||||
enable_markup: true
|
||||
_help_ruler_pattern:
|
||||
- !!python/unicode 'Regular expression to match rulers in comments'
|
||||
- !!python/unicode 'default=r''^\s*[^\w\s]{3}.*[^\w\s]{3}$'''
|
||||
ruler_pattern: !!python/unicode '^\s*[^\w\s]{3}.*[^\w\s]{3}$'
|
||||
_help_enum_char:
|
||||
- !!python/unicode 'What character to use as punctuation after numerals in an'
|
||||
- !!python/unicode 'enumerated list'
|
||||
enum_char: .
|
||||
_help_bullet_char:
|
||||
- !!python/unicode 'What character to use for bulleted lists'
|
||||
bullet_char: '*'
|
||||
_help_lint: !!python/unicode 'Options affecting the linter'
|
||||
lint:
|
||||
_help_function_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid function names'
|
||||
function_pattern: !!python/unicode '[0-9a-z_]+'
|
||||
_help_disabled_codes:
|
||||
- !!python/unicode 'a list of lint codes to disable'
|
||||
disabled_codes: []
|
||||
_help_min_statement_spacing:
|
||||
- !!python/unicode 'Require at least this many newlines between statements'
|
||||
min_statement_spacing: 1
|
||||
_help_macro_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid macro names'
|
||||
macro_pattern: !!python/unicode '[0-9A-Z_]+'
|
||||
_help_public_var_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid names for'
|
||||
- !!python/unicode 'publicdirectory variables'
|
||||
public_var_pattern: !!python/unicode '[0-9A-Z][0-9A-Z_]+'
|
||||
max_statements: 50
|
||||
_help_max_conditionals_custom_parser:
|
||||
- !!python/unicode 'In the heuristic for C0201, how many conditionals to match'
|
||||
- !!python/unicode 'within a loop in before considering the loop a parser.'
|
||||
max_conditionals_custom_parser: 2
|
||||
_help_global_var_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid names for'
|
||||
- !!python/unicode 'variables with global scope'
|
||||
global_var_pattern: !!python/unicode '[0-9A-Z][0-9A-Z_]+'
|
||||
_help_keyword_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid names for'
|
||||
- !!python/unicode 'keywords used in functions or macros'
|
||||
keyword_pattern: !!python/unicode '[0-9A-Z_]+'
|
||||
max_arguments: 5
|
||||
_help_private_var_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid names for'
|
||||
- !!python/unicode 'privatedirectory variables'
|
||||
private_var_pattern: !!python/unicode '_[0-9a-z_]+'
|
||||
max_localvars: 15
|
||||
max_branches: 12
|
||||
_help_local_var_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid names for'
|
||||
- !!python/unicode 'variables with local scope'
|
||||
local_var_pattern: !!python/unicode '[0-9a-z_]+'
|
||||
_help_max_statement_spacing:
|
||||
- !!python/unicode 'Require no more than this many newlines between statements'
|
||||
max_statement_spacing: 1
|
||||
_help_internal_var_pattern:
|
||||
- !!python/unicode 'regular expression pattern describing valid names for'
|
||||
- !!python/unicode 'variables with global scope (but internal semantic)'
|
||||
internal_var_pattern: !!python/unicode '_[0-9A-Z][0-9A-Z_]+'
|
||||
max_returns: 6
|
||||
_help_misc: !!python/unicode 'Miscellaneous configurations options.'
|
||||
misc:
|
||||
_help_per_command:
|
||||
- !!python/unicode 'A dictionary containing any per-command configuration'
|
||||
- !!python/unicode 'overrides. Currently only `command_case` is supported.'
|
||||
per_command: {}
|
||||
_help_parse: !!python/unicode 'Options affecting listfile parsing'
|
||||
parse:
|
||||
_help_additional_commands:
|
||||
- !!python/unicode 'Specify structure for custom cmake functions'
|
||||
additional_commands:
|
||||
!!python/unicode 'foo':
|
||||
!!python/unicode 'flags':
|
||||
- !!python/unicode 'BAR'
|
||||
- !!python/unicode 'BAZ'
|
||||
!!python/unicode 'kwargs':
|
||||
!!python/unicode 'HEADERS': !!python/unicode '*'
|
||||
!!python/unicode 'DEPENDS': !!python/unicode '*'
|
||||
!!python/unicode 'SOURCES': !!python/unicode '*'
|
||||
_help_encode: !!python/unicode 'Options effecting file encoding'
|
19
ext/libpqxx-7.7.3/.github/workflows/stale.yml
vendored
Normal file
19
ext/libpqxx-7.7.3/.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "30 1 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'There has been no activity on this ticket. Consider closing it.'
|
||||
stale-pr-message: 'There has been no activity on this pull request. Complete it or drop it.'
|
||||
stale-issue-label: 'no-issue-activity'
|
||||
stale-pr-label: 'no-pr-activity'
|
49
ext/libpqxx-7.7.3/.gitignore
vendored
Normal file
49
ext/libpqxx-7.7.3/.gitignore
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
autom4te.cache
|
||||
build-*.out
|
||||
ChangeLog
|
||||
CMakeFiles/CMakeTmp
|
||||
confdefs.h
|
||||
config.log
|
||||
config.status
|
||||
conftest
|
||||
conftest.cpp
|
||||
conftest.err
|
||||
doc/_build
|
||||
doc/Doxyfile
|
||||
doc/html/Reference/*.css
|
||||
doc/html/Reference/*.html
|
||||
doc/html/Reference/*.js
|
||||
doc/html/Reference/*.png
|
||||
doc/html/Reference/*.map
|
||||
doc/html/Reference/*.md5
|
||||
doc/reference-stamp
|
||||
include/pqxx/config-*-*.h
|
||||
include/pqxx/config.h
|
||||
include/pqxx/stamp-h1
|
||||
libpqxx.pc
|
||||
libpqxx-*.tar.gz
|
||||
libtool
|
||||
pqxx-config
|
||||
pqxxlo.txt
|
||||
test/pqxxlo.txt
|
||||
tools/pqxxthreadsafety
|
||||
tools/rmlo
|
||||
README
|
||||
win32/common
|
||||
**/Makefile
|
||||
**/*.la
|
||||
**/*.lo
|
||||
**/*.o
|
||||
**/*.out
|
||||
**/.*.swp
|
||||
**/.swp
|
||||
**/*.tmp
|
||||
**/.deps
|
||||
**/.libs
|
||||
**/*~
|
||||
**/lint.log
|
||||
**/lint.trs
|
||||
**/runner
|
||||
**/runner.log
|
||||
**/runner.trs
|
||||
**/test-suite.log
|
9
ext/libpqxx-7.7.3/.lgtm.yml
Normal file
9
ext/libpqxx-7.7.3/.lgtm.yml
Normal file
@ -0,0 +1,9 @@
|
||||
# Config file for lgtm.com static analysis.
|
||||
|
||||
path_classifiers:
|
||||
test:
|
||||
- test
|
||||
generated:
|
||||
- aclocal.m4
|
||||
- configure
|
||||
- ltmain.sh
|
3
ext/libpqxx-7.7.3/.lift/ignoreFiles
Normal file
3
ext/libpqxx-7.7.3/.lift/ignoreFiles
Normal file
@ -0,0 +1,3 @@
|
||||
# Make Sonatype Lift ignore these generated files.
|
||||
configure
|
||||
config/*
|
4
ext/libpqxx-7.7.3/AUTHORS
Normal file
4
ext/libpqxx-7.7.3/AUTHORS
Normal file
@ -0,0 +1,4 @@
|
||||
Jeroen T. Vermeulen. Wrote the code.
|
||||
Ray Dassen. Did most of the autoconf etc. stuff.
|
||||
|
||||
Lots of others helped with various other contributions.
|
272
ext/libpqxx-7.7.3/BUILDING-cmake.md
Normal file
272
ext/libpqxx-7.7.3/BUILDING-cmake.md
Normal file
@ -0,0 +1,272 @@
|
||||
Building using CMake
|
||||
====================
|
||||
|
||||
The build requires the full PostgreSQL development package. That package must
|
||||
be installed before you can build libpqxx.
|
||||
|
||||
The instructions will assume that you're working from a command-line shell.
|
||||
If you prefer to work from an IDE, you'll have to know how your IDE likes to
|
||||
do things, and you'll want to follow the shell instructions as a guide.
|
||||
|
||||
I'm not too familiar with CMake, and this build relies heavily on contributions
|
||||
from users. If you see something wrong here, please file a bug and explain, in
|
||||
simple words, what needs changing and why.
|
||||
|
||||
|
||||
Quick start
|
||||
-----------
|
||||
|
||||
If you just want to get it built and installed quickly, run `cmake` from the
|
||||
root of the libpqxx source tree. This configures your build.
|
||||
|
||||
Then compile libpqxx by running:
|
||||
|
||||
```shell
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
To install in the default location:
|
||||
|
||||
```shell
|
||||
cmake --install .
|
||||
```
|
||||
|
||||
|
||||
Stages
|
||||
------
|
||||
|
||||
I'll explain the main build steps in more detail below, but here's a quick
|
||||
rundown:
|
||||
1. Configure
|
||||
2. Compile
|
||||
3. Test
|
||||
4. Install
|
||||
5. Use
|
||||
|
||||
The Test step is optional.
|
||||
|
||||
|
||||
Configure
|
||||
---------
|
||||
|
||||
Run `cmake` to configure your build. It figures out various parameters, such
|
||||
as where libpq and its headers are, which C++ features your compiler supports,
|
||||
and which options your compiler needs. CMake generates configuration for your
|
||||
build tool: `Makefile`s for `make`, or a Solution (".sln") file for MSVC's
|
||||
`msbuild`, and so on.
|
||||
|
||||
At this stage you can also override those options yourself. e.g. to instruct
|
||||
the compiler to look for libpq in a non-standard place, or to use a different
|
||||
compiler, or pass different compiler flags. Don't try to specify those while
|
||||
doing the actual compile; set them once when running `cmake`.
|
||||
|
||||
Let's say `$BUILD` is the directory where you want to build libpqxx, and
|
||||
`$SRC` is where its source code is. So for example, the readme file will be at
|
||||
`$SRC/README.md`.
|
||||
|
||||
In the simplest case, you just do:
|
||||
|
||||
```shell
|
||||
cd $BUILD
|
||||
cmake $SRC
|
||||
```
|
||||
|
||||
Add CMake options as needed. There's more about the options below. I'll also
|
||||
explain the two directories.
|
||||
|
||||
|
||||
### Cheat sheet
|
||||
|
||||
Here are some popular `cmake` options for libpqxx:
|
||||
* `-DSKIP_BUILD_TEST=on` skips compiling libpqxx's tests.
|
||||
* `-DBUILD_SHARED_LIBS=on` to build a shared library.
|
||||
* `-DBUILD_SHARED_LIBS=off` to build a static library.
|
||||
* `-DBUILD_DOC=on` to build documentation.
|
||||
* `-DINSTALL_TEST=on` to install test executor binary.
|
||||
|
||||
On Windows, I recommend building libpqxx as a shared library and bundling it
|
||||
with your application. On other platforms I would prefer a static library.
|
||||
|
||||
Building the documentation requires some tools to be installed. It takes at
|
||||
least Doxygen, but there's no list of requirements. The way to get this set up
|
||||
is to just try it and see what it's missing.
|
||||
|
||||
|
||||
### Generators
|
||||
|
||||
You can also choose your own build tool by telling CMake to use a particular
|
||||
"generator." For example, here's how to force use of `make`:
|
||||
|
||||
```shell
|
||||
cmake -G 'Unix Makefiles'
|
||||
```
|
||||
|
||||
Or if you prefer to build using `ninja` instead:
|
||||
|
||||
```shell
|
||||
cmake -G Ninja
|
||||
```
|
||||
|
||||
There are many more options. You may prefer yet a different build tool.
|
||||
|
||||
|
||||
### Finding libpq
|
||||
|
||||
The CMake step tries to figure out where libpq is, using Cmake's `find_package`
|
||||
function. If that doesn't work, or if you want a libpq in a different location
|
||||
from the one it finds, there are two ways to override it.
|
||||
|
||||
The first is to set the individual include and link paths.
|
||||
|
||||
To make the build look for the libpq headers in some directory `$DIR`, add
|
||||
these options:
|
||||
* `-DPostgreSQL_TYPE_INCLUDE_DIR=$DIR`
|
||||
* `-DPostgreSQL_INCLUDE_DIR=$DIR`
|
||||
|
||||
To make the build look for the libpq library binary in a directory `$DIR`, add
|
||||
this option:
|
||||
* `-DPostgreSQL_LIBRARY_DIR=$DIR`
|
||||
|
||||
The second, easier way requires CMake 3.12 or better. Here, you specify a path
|
||||
to a full PostgreSQL build tree. You do this (again for some directory `$DIR`)
|
||||
by simply passing this cmake option: `-DPostgreSQL_ROOT=$DIR`
|
||||
|
||||
|
||||
### Source and Build trees
|
||||
|
||||
Where should you run `cmake`?
|
||||
|
||||
Two directories matter when building libpqxx: the _source tree_ (where the
|
||||
libpqxx source code is) and the _build tree_ (where you want your build
|
||||
artefacts). Here I will call them `$SRC` and `$BUILD`, but you can call them
|
||||
anything you like.
|
||||
|
||||
They can be one and the same, if you like. It's convenient, but less clean, as
|
||||
source code and build artefacts will exist in the same directory tree. If
|
||||
you're going to delete the source tree after installing, of course it's fine to
|
||||
make a mess in there.
|
||||
|
||||
|
||||
Compile
|
||||
-------
|
||||
|
||||
To compile, run:
|
||||
|
||||
```shell
|
||||
cmake --build $BUILD
|
||||
```
|
||||
|
||||
(Where `$BUILD` is again the directory where you wish to do the build.)
|
||||
|
||||
This command will invoke your build tool. Other ways to do the same thing
|
||||
would be...
|
||||
* With Unix Makefiles: `make`
|
||||
* With Ninja: `ninja`
|
||||
* With Visual Studio: `msbuild libpqxx.sln`
|
||||
* etc.
|
||||
|
||||
Depending on your build tool, you may want to speed this up by adding an option
|
||||
like `-j 16`, where `16` is an example of how many processes you might want to
|
||||
run in parallel. The optimal number depends on your available CPUs and memory.
|
||||
If you have enough memory, usually the number of CPUs will be a good starting
|
||||
point for the right number. Don't use this option with Ninja though. It
|
||||
figures things out for itself.
|
||||
|
||||
|
||||
Test
|
||||
----
|
||||
|
||||
Of course libpqxx comes with a test suite, to check that the library is
|
||||
functioning correctly.
|
||||
|
||||
You can run it, but there's one caveat: you need to give it a database where it
|
||||
can log in, without a password or any other parameters, and try out various
|
||||
things.
|
||||
|
||||
And when I say you need to "give" it a database, I really mean "give." The
|
||||
test suite will create and drop tables. Those will all have names prefixed
|
||||
with "pqxx", so it's probably safe to use a database you already had, but if
|
||||
any of the items in your database happen to have names starting with `pqxx`,
|
||||
tough luck. They're fair game.
|
||||
|
||||
Enter this in your shell to build and run the tests:
|
||||
|
||||
```shell
|
||||
test/runner
|
||||
```
|
||||
|
||||
|
||||
### Configuring the test database
|
||||
|
||||
But what if you do need a password to log into your test database? Or, what if
|
||||
it's running on a different system so you need to pass that machine's address?
|
||||
What if it's not running on the default port?
|
||||
|
||||
You can set these parameters for the test suite, or for any other libpq-based
|
||||
application, using the following environment variables. (They only set default
|
||||
values, so they won't override parameters that the application sets in some
|
||||
other way.)
|
||||
* `PGHOST` — the IP address where we can contact the database's socket. Or
|
||||
for a Unix domain socket, its absolute path on the filesystem.
|
||||
* `PGPORT` — TCP port number on which we can connect to the database.
|
||||
* `PGDATABASE` — the name of the database to which you wish to connect.
|
||||
* `PGUSER` — user name under which you wish to log in on the database.
|
||||
* `PGPASSWORD` — user name's password for accessing the database.
|
||||
|
||||
See the full list at https://www.postgresql.org/docs/current/libpq-envars.html
|
||||
|
||||
**Be careful with passwords,** by the way. Depending on your operating system
|
||||
and configuration, an attacker with access to your machine could try to read
|
||||
your password if you set it on the command line:
|
||||
* Your shell may keep a log of the commands you have entered.
|
||||
* Environment variables may be visible to other users on the system.
|
||||
|
||||
If at all possible, rely on postgres "peer authentication." Once set up, it is
|
||||
both more secure and more convenient than passwords.
|
||||
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
Once you've built libpqxx, CMake can also help you install the library and
|
||||
headers on your system. The default installation location will vary from one
|
||||
operating system to another, but you can set it explicitly.
|
||||
|
||||
Let's say you've got your finished build in `$BUILD`, and you want to install
|
||||
it to your system's default install location. The command for this is:
|
||||
|
||||
```shell
|
||||
cmake --install $BUILD
|
||||
```
|
||||
|
||||
But you may want to install to some other location. Let's call it `$DEST`.
|
||||
`$DEST` might be something like `/usr/local` on a Unix-like system, or
|
||||
something like `D:\Software` on a Windows system.
|
||||
|
||||
To install to `$DEST`, run:
|
||||
|
||||
```shell
|
||||
cmake --install $BUILD --prefix $DEST
|
||||
```
|
||||
|
||||
|
||||
Use
|
||||
---
|
||||
|
||||
Other projects can include libpqxx in their CMake builds.
|
||||
|
||||
`@abrownsword` uses this configuration:
|
||||
|
||||
```cmake
|
||||
set(libpqxxdir "libpqxx-${LIBVERSION}") # LIBVERSION set above
|
||||
set(SKIP_BUILD_TEST on)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
# Used this instead of FindLibrary.
|
||||
# Setting PostgresSQL_INCLUDE_DIRS externally.
|
||||
set(PostgreSQL_FOUND true)
|
||||
set(PostgresSQL_INCLUDE_DIR ${PostgresSQL_INCLUDE_DIRS})
|
||||
set(PostgresSQL_TYPE_INCLUDE_DIR ${PostgresSQL_INCLUDE_DIRS})
|
||||
|
||||
add_subdirectory(${libpqxxdir})
|
||||
```
|
275
ext/libpqxx-7.7.3/BUILDING-configure.md
Normal file
275
ext/libpqxx-7.7.3/BUILDING-configure.md
Normal file
@ -0,0 +1,275 @@
|
||||
Building using `configure`
|
||||
==========================
|
||||
|
||||
The build requires `libpq`, the C client library for PostgreSQL. This library
|
||||
must be installed before you can build libpqxx. You'll need the headers as
|
||||
well as the library binary.
|
||||
|
||||
The instructions will assume that you're working from a command-line shell.
|
||||
If you prefer to work from an IDE, you'll have to know how your IDE likes to
|
||||
do things, and you'll want to follow the shell instructions as a guide.
|
||||
|
||||
|
||||
Quick start
|
||||
-----------
|
||||
|
||||
If you just want to get it built and installed quickly, try:
|
||||
|
||||
```shell
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Want more detail? Read on.
|
||||
|
||||
|
||||
Stages
|
||||
------
|
||||
|
||||
I'll explain the main build steps in more detail below, but here's a quick
|
||||
overview:
|
||||
1. Configure
|
||||
2. Compile
|
||||
3. Test
|
||||
4. Install
|
||||
|
||||
The Test step is optional.
|
||||
|
||||
|
||||
Configure
|
||||
---------
|
||||
|
||||
The `configure` script configures your build. It figures out various
|
||||
parameters, such as where libpq and its headers are, which C++ features your
|
||||
compiler supports, and which options your compiler needs. It generates
|
||||
Makefiles, which in turn tell the `make` utility how to perform tasks such as
|
||||
compiling libpqxx, running tests, cleaning up after itself, and installing
|
||||
libpqxx.
|
||||
|
||||
The `configure` step is also where you can set these options, e.g. to instruct
|
||||
the compiler to look for libpq in a non-standard place, or to use a different
|
||||
compiler, or pass different compiler flags. Don't try to specify those while
|
||||
doing the actual compile; set them once when running `configure`.
|
||||
|
||||
Let's say `$BUILD` is the directory where you want to build libpqxx, and
|
||||
`$SRC` is where its source code is. So for example, the readme file will be at
|
||||
`$SRC/README.md`.
|
||||
|
||||
In the simplest case, you just do:
|
||||
|
||||
```shell
|
||||
cd $BUILD
|
||||
$SRC/configure
|
||||
```
|
||||
|
||||
Add `configure` options as needed. There's more about the options below, or in
|
||||
the output of `configure --help`. I'll also explain the two directories.
|
||||
|
||||
|
||||
### Cheat sheet
|
||||
|
||||
Here are some popular `configure` options:
|
||||
* `--disable-documentation` skips building of the documentation.
|
||||
* `CXXFLAGS=-O0` disables optimisation. Slower code, but faster build.
|
||||
* `CXXFLAGS=-O3` asks for _more_ optimisation. Faster code, slower build.
|
||||
* `CXX=clang++` compiles with `clang++` as the compiler.
|
||||
* `--enable-maintainer-mode` makes the compiler more pedantic about the code.
|
||||
* `--enable-audit` enables expensive run-time checks for debugging.
|
||||
* `--with-postgres-lib=$DIR` looks for libpq in `$DIR`.
|
||||
* `--with-postgres-include=$DIR` looks for the libpq headers in `$DIR`.
|
||||
* `--prefix=$PATH` prepares to install libpqxx in `$PATH`.
|
||||
* `--enable-shared` enables compilation of libpqxx as a shared library.
|
||||
* `--disable-shared` disbles compilation of libpqxx as a shared library.
|
||||
* `--enable-static` enables compilation of libpqxx as a static library.
|
||||
* `--disable-static` disables compilation of libpqxx as a static library.
|
||||
* `--help` shows you a lot more of the options.
|
||||
|
||||
So for example, to get a very quick build but produce very inefficient code:
|
||||
|
||||
```shell
|
||||
./configure --disable-documentation CXXFLAGS=-O0
|
||||
```
|
||||
|
||||
|
||||
Or if you want to pull out all the stops to find problems in the code:
|
||||
|
||||
```shell
|
||||
./configure --enable-maintainer-mode --enable-audit CXXFLAGS=-O3
|
||||
```
|
||||
|
||||
(Requesting `-O3` optimisation will make some compilers perform extra analysis
|
||||
which may, as a side effect, cause them to notice and warn about certain kinds
|
||||
of mistakes in the code, such as occasionally-unused variables.)
|
||||
|
||||
|
||||
### Finding libpq
|
||||
|
||||
One of `configure`'s most important jobs in the libpqxx build is to find the
|
||||
headers and library for libpq. It has three ways of finding those:
|
||||
1. Asking a popular tool called `pkg-config`, if installed.
|
||||
2. Asking postgres' deprecated `pg_config` tool, if installed.
|
||||
3. Through explicit command-line options to `configure`.
|
||||
|
||||
The explicit command-line options are `--with-postgres-lib` (for the libpq
|
||||
library binary) and `--with-postgres-include` (for the libpq headers).
|
||||
|
||||
If you want to use a version of libpq that's not installed in a standard
|
||||
location, e.g. if you're cross-compiling to produce a binary for a different
|
||||
CPU architecture than your native system's, use the explicit options.
|
||||
|
||||
|
||||
### Where does the `configure` script come from?
|
||||
|
||||
I didn't write the `configure` script. It was generated by GNU `autoconf` and
|
||||
related GNU tools. There's a script to re-generate it, called `autogen.sh`.
|
||||
|
||||
The contents of `configure` are based on a higher-level script called
|
||||
`configure.ac`. This is where I script checks for specific features in libpq
|
||||
or the compiler. The `configure` script adds a lot of built-in items that I
|
||||
don't need to worry about, such as figuring out exactly how your build tools
|
||||
work.
|
||||
|
||||
Don't try to debug `configure` yourself if you can help it. It's very hard to
|
||||
read, partly because it's automatically generated, but also because it is
|
||||
engineered to work with an extremely broad range of shells, compilers, tools,
|
||||
and operating systems. If you're going to do a "deep dive," try looking at
|
||||
`configure.ac` instead.
|
||||
|
||||
|
||||
### Source and Build trees
|
||||
|
||||
Where should you run `configure`?
|
||||
|
||||
Two directories matter when building libpqxx: the _source tree_ (where the
|
||||
libpqxx source code is) and the _build tree_ (where you want your build
|
||||
artefacts). Here I will call them `$SRC` and `$BUILD`, but you can call them
|
||||
anything you like.
|
||||
|
||||
They can be one and the same, if you like. It's convenient, but less clean, as
|
||||
source code and build artefacts will exist in the same directory tree. If
|
||||
you're going to delete the source tree after installing, of course it's fine to
|
||||
make a mess in there.
|
||||
|
||||
|
||||
Compile
|
||||
-------
|
||||
|
||||
To start the compile, run the `make` tool. It will go through all the steps to
|
||||
produce a libpqxx library binary.
|
||||
|
||||
Beware though, it only runs _one_ compiler process at a time. That could take
|
||||
a while. Use the `-j` option to make it run concurrent processes, e.g.:
|
||||
|
||||
```shell
|
||||
make -j8
|
||||
```
|
||||
|
||||
Very roughly speaking, it's probably fastest if you run one process per CPU
|
||||
core in your system. If you have the `nproc` utility installed:
|
||||
|
||||
```shell
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
If you want a very fast build and don't mind missing out on efficient code or
|
||||
documentation, tweak the Configure step above by adding `configure` options
|
||||
like `CXXFLAGS=-O0` and `--disable-documentation`.
|
||||
|
||||
|
||||
Test
|
||||
----
|
||||
|
||||
Of course libpqxx comes with a test suite, to check that the library is
|
||||
functioning correctly.
|
||||
|
||||
You can run it, but there's one caveat: you need to give it a database where it
|
||||
can log in, without a password or any other parameters, and try out various
|
||||
things.
|
||||
|
||||
And when I say you need to "give" it a database, I really mean "give." The
|
||||
test suite will create and drop tables. Those will all have names prefixed
|
||||
with "pqxx", so it's probably safe to use a database you already had, but if
|
||||
any of the items in your database happen to have names starting with `pqxx`,
|
||||
tough luck. They're fair game.
|
||||
|
||||
Enter this in your shell to build and run the tests:
|
||||
|
||||
```shell
|
||||
make check
|
||||
```
|
||||
|
||||
As with compiling, use the `-j` option to make better use of your CPUs. For
|
||||
example:
|
||||
|
||||
```shell
|
||||
make check -j$(nproc)
|
||||
```
|
||||
|
||||
|
||||
### Configuring the test database
|
||||
|
||||
But what if you do need a password to log into your test database? Or, what if
|
||||
it's running on a different system so you need to pass that machine's address?
|
||||
What if it's not running on the default port?
|
||||
|
||||
You can set these parameters for the test suite, or for any other libpq-based
|
||||
application, using the following environment variables. (They only set default
|
||||
values, so they won't override parameters that the application sets in some
|
||||
other way.)
|
||||
* `PGHOST` — the IP address where we can contact the database's socket. Or
|
||||
for a Unix domain socket, its absolute path on the filesystem.
|
||||
* `PGPORT` —
|
||||
* `PGDATABASE` — the name of the database to which you wish to connect.
|
||||
* `PGUSER` — user name under which you wish to log in on the database.
|
||||
* `PGPASSWORD` — user name's password for accessing the database.
|
||||
|
||||
See the full list at https://www.postgresql.org/docs/current/libpq-envars.html
|
||||
|
||||
**Be careful with passwords,** by the way. Depending on your operating system
|
||||
and configuration, an attacker with access to your machine could try to read
|
||||
your password if you set it on the command line:
|
||||
* Your shell may keep a log of the commands you have entered.
|
||||
* Environment variables may be visible to other users on the system.
|
||||
|
||||
If at all possible, rely on postgres "peer authentication." Once set up, it is
|
||||
both more secure and more convenient than passwords.
|
||||
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
Installing libpqxx will install the library and headers in a location chosen at
|
||||
the time you can the `configure` script. On some systems it defaults to the
|
||||
`/usr/local/` tree, but it may be different in your environment. Or, use the
|
||||
`configure` script's `--prefix` option to set an install location.
|
||||
|
||||
(If you want to see exactly what happens, you can run any `make` command line
|
||||
with the `-n` option, which means: don't actually do this, but print all the
|
||||
commands you would execute if you did. It's a lot of output though.)
|
||||
|
||||
To install, ensure that you have sufficient privileges to write the files to
|
||||
their install locations, and run:
|
||||
|
||||
```shell
|
||||
make install
|
||||
```
|
||||
|
||||
Save your build tree somewhere, so that you will be able to undo installation
|
||||
in the future:
|
||||
|
||||
```shell
|
||||
make uninstall
|
||||
```
|
||||
|
||||
When using the library, make sure the libpqxx headers are in your compiler's
|
||||
include path. (You will no longer need the libpq headers at that time.)
|
||||
|
||||
Also, building an application which uses libpqxx, make sure the libpqxx library
|
||||
binary is in your compiler's library search path. And if the library binary is
|
||||
a shared library, you'll also need it in your loader's search path when running
|
||||
your application.
|
||||
|
||||
This last part goes for libpq as well: when using libpq, make sure you have
|
||||
the libpq library binary in your compiler's library search path, and if it's a
|
||||
shared library, also have it in your loader's search path when running.
|
66
ext/libpqxx-7.7.3/CMakeLists.txt
Normal file
66
ext/libpqxx-7.7.3/CMakeLists.txt
Normal file
@ -0,0 +1,66 @@
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
|
||||
file(READ VERSION VER_FILE_CONTENT)
|
||||
string(STRIP ${VER_FILE_CONTENT} VER_FILE_CONTENT)
|
||||
|
||||
project(
|
||||
libpqxx
|
||||
VERSION ${VER_FILE_CONTENT}
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
if(NOT "${CMAKE_CXX_STANDARD}")
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
option(BUILD_DOC "Build documentation" OFF)
|
||||
|
||||
if(NOT SKIP_BUILD_TEST)
|
||||
option(BUILD_TEST "Build all test cases" ON)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(config)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(include)
|
||||
if(BUILD_DOC)
|
||||
add_subdirectory(doc)
|
||||
endif()
|
||||
if(BUILD_TEST)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# installation
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/libpqxx-config-version.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
install(FILES cmake/libpqxx-config.cmake
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/libpqxx-config-version.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libpqxx
|
||||
)
|
||||
install(
|
||||
EXPORT libpqxx-targets
|
||||
NAMESPACE libpqxx::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libpqxx
|
||||
)
|
||||
# Build tree export
|
||||
export(
|
||||
EXPORT libpqxx-targets
|
||||
NAMESPACE libpqxx::
|
||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/libpqxx-targets.cmake
|
||||
)
|
||||
configure_file(
|
||||
cmake/libpqxx-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/libpqxx-config.cmake
|
||||
COPYONLY
|
||||
)
|
||||
# Package generation
|
||||
set(CPACK_GENERATOR TGZ)
|
||||
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
include(CPack)
|
27
ext/libpqxx-7.7.3/COPYING
Normal file
27
ext/libpqxx-7.7.3/COPYING
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2000-2022 Jeroen T. Vermeulen.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the author, nor the names of other contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
2
ext/libpqxx-7.7.3/INSTALL
Normal file
2
ext/libpqxx-7.7.3/INSTALL
Normal file
@ -0,0 +1,2 @@
|
||||
For installation instructions, see `BUILDING-configure.md` (for the `configure`
|
||||
build) and `BUILDING-cmake.md` (for the CMake build).
|
23
ext/libpqxx-7.7.3/Makefile.am
Normal file
23
ext/libpqxx-7.7.3/Makefile.am
Normal file
@ -0,0 +1,23 @@
|
||||
SUBDIRS = include src test tools config doc
|
||||
EXTRA_DIST = autogen.sh configitems README.md VERSION requirements.json
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in aclocal.m4 config.h.in config.log configure stamp-h.in
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libpqxx.pc
|
||||
|
||||
TESTS = tools/lint
|
||||
|
||||
|
||||
# Generate ChangeLog from git history. It goes all the way back through
|
||||
# the project's git, bzr, svn, and cvs days.
|
||||
dist-hook: ChangeLog
|
||||
|
||||
ChangeLog: configure.ac
|
||||
git log --stat --name-only --date=short --abbrev-commit >$@
|
||||
|
||||
|
||||
# We use README.md, but automake expects plain README.
|
||||
README: README.md
|
||||
ln -s $< $@
|
1253
ext/libpqxx-7.7.3/Makefile.in
Normal file
1253
ext/libpqxx-7.7.3/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
1040
ext/libpqxx-7.7.3/NEWS
Normal file
1040
ext/libpqxx-7.7.3/NEWS
Normal file
File diff suppressed because it is too large
Load Diff
199
ext/libpqxx-7.7.3/README.md
Normal file
199
ext/libpqxx-7.7.3/README.md
Normal file
@ -0,0 +1,199 @@
|
||||
libpqxx
|
||||
=======
|
||||
|
||||
Welcome to libpqxx, the C++ API to the PostgreSQL database management system.
|
||||
|
||||
Home page: http://pqxx.org/development/libpqxx/
|
||||
|
||||
Find libpqxx on Github: https://github.com/jtv/libpqxx
|
||||
|
||||
Documentation on Read The Docs: https://libpqxx.readthedocs.io
|
||||
|
||||
Compiling this package requires PostgreSQL to be installed -- or at least the C
|
||||
headers and library for client development. The library builds on top of
|
||||
PostgreSQL's standard C API, libpq, though your code won't notice.
|
||||
|
||||
If you're getting the code straight from the Git repo, the head of the `master`
|
||||
branch represents the current _development version._ Releases are tags on
|
||||
commits in `master`. For example, to get version 7.1.1:
|
||||
|
||||
git checkout 7.1.1
|
||||
|
||||
|
||||
Upgrade notes
|
||||
-------------
|
||||
|
||||
**The 7.x versions require at least C++17.** Make sure your compiler is up to
|
||||
date. For libpqxx 8.x you will need at least C++20.
|
||||
|
||||
Also, **7.0 makes some breaking changes in rarely used APIs:**
|
||||
* There is just a single `connection` class. It connects immediately.
|
||||
* Custom `connection` classes are no longer supported.
|
||||
* It's no longer possible to reactivate a connection once it's been closed.
|
||||
* The API for defining string conversions has changed.
|
||||
|
||||
If you're defining your own type conversions, **7.1 requires one additional
|
||||
field in your `nullness` traits.**
|
||||
|
||||
|
||||
Building libpqxx
|
||||
----------------
|
||||
|
||||
There are two different ways of building libpqxx from the command line:
|
||||
1. Using CMake, on any system which supports it.
|
||||
2. On Unix-like systems, using a `configure` script.
|
||||
|
||||
"Unix-like" systems include GNU/Linux, Apple macOS and the BSD family, AIX,
|
||||
HP-UX, Irix, Solaris, etc. Even on Microsoft Windows, a Unix-like environment
|
||||
such as WSL, Cygwin, or MinGW should work.
|
||||
|
||||
You'll find detailed build and install instructions in `BUILDING-configure.md`
|
||||
and `BUILDING-cmake.md`, respectively.
|
||||
|
||||
And if you're working with Microsoft Visual Studio, have a look at Gordon
|
||||
Elliott's
|
||||
[
|
||||
Easy-PQXX Build for Windows Visual Studio
|
||||
](https://github.com/GordonLElliott/Easy-PQXX-Build-for-Windows-Visual-Studio)
|
||||
project.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Building the library, if you have the right tools installed, generates HTML
|
||||
documentation in the `doc/` directory. It is based on the headers in
|
||||
`include/pqxx/` and text in `include/pqxx/doc/`. This documentation is also
|
||||
available online at [readthedocs](https://libpqxx.readthedocs.io).
|
||||
|
||||
|
||||
Programming with libpqxx
|
||||
------------------------
|
||||
|
||||
Your first program will involve the libpqxx classes `connection` (see the
|
||||
`pqxx/connection.hxx` header), and `work` (a convenience alias for
|
||||
`transaction<>` which conforms to the interface defined in
|
||||
`pqxx/transaction_base.hxx`).
|
||||
|
||||
These `*.hxx` headers are not the ones you include in your program. Instead,
|
||||
include the versions without filename suffix (e.g. `pqxx/connection`). Those
|
||||
will include the actual .hxx files for you. This was done so that includes are
|
||||
in standard C++ style (as in `<iostream>` etc.), but an editor will still
|
||||
recognize them as files containing C++ code.
|
||||
|
||||
Continuing the list of classes, you will most likely also need the result class
|
||||
(`pqxx/result.hxx`). In a nutshell, you create a `connection` based on a
|
||||
Postgres connection string (see below), create a `work` in the context of that
|
||||
connection, and run one or more queries on the work which return `result`
|
||||
objects. The results are containers of rows of data, each of which you can
|
||||
treat as an array of strings: one for each field in the row. It's that simple.
|
||||
|
||||
Here is a simple example program to get you going, with full error handling:
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <pqxx/pqxx>
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Connect to the database.
|
||||
pqxx::connection C;
|
||||
std::cout << "Connected to " << C.dbname() << '\n';
|
||||
|
||||
// Start a transaction.
|
||||
pqxx::work W{C};
|
||||
|
||||
// Perform a query and retrieve all results.
|
||||
pqxx::result R{W.exec("SELECT name FROM employee")};
|
||||
|
||||
// Iterate over results.
|
||||
std::cout << "Found " << R.size() << "employees:\n";
|
||||
for (auto row: R)
|
||||
std::cout << row[0].c_str() << '\n';
|
||||
|
||||
// Perform a query and check that it returns no result.
|
||||
std::cout << "Doubling all employees' salaries...\n";
|
||||
W.exec0("UPDATE employee SET salary = salary*2");
|
||||
|
||||
// Commit the transaction.
|
||||
std::cout << "Making changes definite: ";
|
||||
W.commit();
|
||||
std::cout << "OK.\n";
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Connection strings
|
||||
------------------
|
||||
|
||||
Postgres connection strings state which database server you wish to connect to,
|
||||
under which username, using which password, and so on. Their format is defined
|
||||
in the documentation for libpq, the C client interface for PostgreSQL.
|
||||
Alternatively, these values may be defined by setting certain environment
|
||||
variables as documented in e.g. the manual for psql, the command line interface
|
||||
to PostgreSQL. Again the definitions are the same for libpqxx-based programs.
|
||||
|
||||
The connection strings and variables are not fully and definitively documented
|
||||
here; this document will tell you just enough to get going. Check the
|
||||
PostgreSQL documentation for authoritative information.
|
||||
|
||||
The connection string consists of attribute=value pairs separated by spaces,
|
||||
e.g. "user=john password=1x2y3z4". The valid attributes include:
|
||||
* `host` —
|
||||
Name of server to connect to, or the full file path (beginning with a
|
||||
slash) to a Unix-domain socket on the local machine. Defaults to
|
||||
"/tmp". Equivalent to (but overrides) environment variable PGHOST.
|
||||
* `hostaddr` —
|
||||
IP address of a server to connect to; mutually exclusive with "host".
|
||||
* `port` —
|
||||
Port number at the server host to connect to, or socket file name
|
||||
extension for Unix-domain connections. Equivalent to (but overrides)
|
||||
environment variable PGPORT.
|
||||
* `dbname` —
|
||||
Name of the database to connect to. A single server may host multiple
|
||||
databases. Defaults to the same name as the current user's name.
|
||||
Equivalent to (but overrides) environment variable PGDATABASE.
|
||||
* `user` —
|
||||
User name to connect under. This defaults to the name of the current
|
||||
user, although PostgreSQL users are not necessarily the same thing as
|
||||
system users.
|
||||
* `requiressl` —
|
||||
If set to 1, demands an encrypted SSL connection (and fails if no SSL
|
||||
connection can be created).
|
||||
|
||||
Settings in the connection strings override the environment variables, which in
|
||||
turn override the default, on a variable-by-variable basis. You only need to
|
||||
define those variables that require non-default values.
|
||||
|
||||
|
||||
Linking with libpqxx
|
||||
--------------------
|
||||
|
||||
To link your final program, make sure you link to both the C-level libpq library
|
||||
and the actual C++ library, libpqxx. With most Unix-style compilers, you'd do
|
||||
this using the options
|
||||
|
||||
-lpqxx -lpq
|
||||
|
||||
while linking. Both libraries must be in your link path, so the linker knows
|
||||
where to find them. Any dynamic libraries you use must also be in a place
|
||||
where the loader can find them when loading your program at runtime.
|
||||
|
||||
Some users have reported problems using the above syntax, however, particularly
|
||||
when multiple versions of libpqxx are partially or incorrectly installed on the
|
||||
system. If you get massive link errors, try removing the "-lpqxx" argument from
|
||||
the command line and replacing it with the name of the libpqxx library binary
|
||||
instead. That's typically libpqxx.a, but you'll have to add the path to its
|
||||
location as well, e.g. /usr/local/pqxx/lib/libpqxx.a. This will ensure that the
|
||||
linker will use that exact version of the library rather than one found
|
||||
elsewhere on the system, and eliminate worries about the exact right version of
|
||||
the library being installed with your program..
|
1
ext/libpqxx-7.7.3/VERSION
Normal file
1
ext/libpqxx-7.7.3/VERSION
Normal file
@ -0,0 +1 @@
|
||||
7.7.3
|
1187
ext/libpqxx-7.7.3/aclocal.m4
vendored
Normal file
1187
ext/libpqxx-7.7.3/aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
30
ext/libpqxx-7.7.3/appveyor.yml
Normal file
30
ext/libpqxx-7.7.3/appveyor.yml
Normal file
@ -0,0 +1,30 @@
|
||||
# Configuration for test runs in Appveyor.
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2022
|
||||
services: postgresql13
|
||||
# Run CMake to build libpqxx.sln.
|
||||
before_build:
|
||||
- cmd: >-
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
|
||||
cmake -DBUILD_SHARED_LIBS=1 -DCMAKE_CXX_STANDARD=23
|
||||
configuration: Release
|
||||
build:
|
||||
parallel: true
|
||||
project: libpqxx.sln
|
||||
test_script:
|
||||
- ps: >-
|
||||
$env:Path += ";.\src\Release;C:\Program Files\PostgreSQL\13\bin"
|
||||
|
||||
$env:PGUSER = "postgres"
|
||||
|
||||
$env:PGPASSWORD = "Password12!"
|
||||
|
||||
.\test\Release\runner.exe
|
||||
notifications:
|
||||
- provider: Email
|
||||
subject: 'libpqxx: AppVeyor build failure'
|
||||
message: The libpqxx AppVeyor build has failed.
|
||||
on_build_success: false
|
||||
on_build_failure: true
|
||||
on_build_status_changed: false
|
44
ext/libpqxx-7.7.3/autogen.sh
Executable file
44
ext/libpqxx-7.7.3/autogen.sh
Executable file
@ -0,0 +1,44 @@
|
||||
#! /bin/sh
|
||||
# Run this to generate the configure script etc.
|
||||
|
||||
set -eu
|
||||
|
||||
PQXXVERSION=$(./tools/extract_version)
|
||||
PQXX_ABI=$(./tools/extract_version --abi)
|
||||
PQXX_MAJOR=$(./tools/extract_version --major)
|
||||
PQXX_MINOR=$(./tools/extract_version --minor)
|
||||
echo "libpqxx version $PQXXVERSION"
|
||||
echo "libpqxx ABI version $PQXX_ABI"
|
||||
|
||||
substitute() {
|
||||
sed -e "s/@PQXXVERSION@/$PQXXVERSION/g" \
|
||||
-e "s/@PQXX_MAJOR@/$PQXX_MAJOR/g" \
|
||||
-e "s/@PQXX_MINOR@/$PQXX_MINOR/g" \
|
||||
-e "s/@PQXX_ABI@/$PQXX_ABI/g" \
|
||||
"$1"
|
||||
}
|
||||
|
||||
|
||||
# Use templating system to generate various Makefiles.
|
||||
expand_templates() {
|
||||
for template in "$@"
|
||||
do
|
||||
./tools/template2mak.py "$template" "${template%.template}"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# We have two kinds of templates. One uses our custom templating tool. And
|
||||
# a few others simply have some substitutions done.
|
||||
expand_templates $(find -name \*.template)
|
||||
substitute include/pqxx/version.hxx.template >include/pqxx/version.hxx
|
||||
substitute include/pqxx/doc/mainpage.md.template >include/pqxx/doc/mainpage.md
|
||||
|
||||
|
||||
autoheader
|
||||
libtoolize --force --automake --copy
|
||||
aclocal -I . -I config/m4
|
||||
automake --add-missing --copy
|
||||
autoconf
|
||||
|
||||
echo "Done."
|
157
ext/libpqxx-7.7.3/cmake/config.cmake
Normal file
157
ext/libpqxx-7.7.3/cmake/config.cmake
Normal file
@ -0,0 +1,157 @@
|
||||
function(detect_code_compiled code macro msg)
|
||||
message(STATUS "Detecting ${msg}")
|
||||
check_cxx_source_compiles("${code}" "${macro}" FAIL_REGEX "warning")
|
||||
if(${macro})
|
||||
message(STATUS "Detecting ${msg} - supported")
|
||||
else()
|
||||
message(STATUS "Detecting ${msg} - not supported")
|
||||
endif()
|
||||
endfunction(detect_code_compiled)
|
||||
|
||||
include(CheckIncludeFileCXX)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckSymbolExists)
|
||||
include(CMakeDetermineCompileFeatures)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
if(NOT PostgreSQL_FOUND)
|
||||
if(POLICY CMP0074)
|
||||
cmake_policy(PUSH)
|
||||
# CMP0074 is `OLD` by `cmake_minimum_required(VERSION 3.7)`,
|
||||
# sets `NEW` to enable support CMake variable `PostgreSQL_ROOT`.
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
endif()
|
||||
|
||||
find_package(PostgreSQL REQUIRED)
|
||||
|
||||
if(POLICY CMP0074)
|
||||
cmake_policy(POP)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
check_function_exists("poll" PQXX_HAVE_POLL)
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES pq)
|
||||
check_symbol_exists(
|
||||
PQencryptPasswordConn
|
||||
"${PostgreSQL_INCLUDE_DIR}/libpq-fe.h"
|
||||
PQXX_HAVE_PQENCRYPTPASSWORDCONN)
|
||||
check_symbol_exists(
|
||||
PQenterPipelineMode
|
||||
"${PostgreSQL_INCLUDE_DIR}/libpq-fe.h"
|
||||
PQXX_HAVE_PQ_PIPELINE)
|
||||
|
||||
cmake_determine_compile_features(CXX)
|
||||
cmake_policy(SET CMP0057 NEW)
|
||||
|
||||
# check_cxx_source_compiles requires CMAKE_REQUIRED_DEFINITIONS to specify
|
||||
# compiling arguments.
|
||||
# Wordaround: Push CMAKE_REQUIRED_DEFINITIONS
|
||||
if(CMAKE_REQUIRED_DEFINITIONS)
|
||||
set(def "${CMAKE_REQUIRED_DEFINITIONS}")
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION})
|
||||
set(CMAKE_REQUIRED_QUIET ON)
|
||||
|
||||
try_compile(
|
||||
PQXX_HAVE_GCC_PURE
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/gcc_pure.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_GCC_VISIBILITY
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/gcc_visibility.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_LIKELY
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/likely.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_CXA_DEMANGLE
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/cxa_demangle.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_CONCEPTS
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/concepts.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_SPAN
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/span.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_MULTIDIMENSIONAL_SUBSCRIPT
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/multidim-subscript.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_CHARCONV_FLOAT
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/charconv_float.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_CHARCONV_INT
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/charconv_int.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_PATH
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/fs.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_THREAD_LOCAL
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/thread_local.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_SLEEP_FOR
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/sleep_for.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_STRERROR_R
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/strerror_r.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_STRERROR_S
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/strerror_s.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_YEAR_MONTH_DAY
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/year_month_day.cxx)
|
||||
try_compile(
|
||||
PQXX_HAVE_CMP
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/cmp.cxx)
|
||||
|
||||
try_compile(
|
||||
need_fslib
|
||||
${PROJECT_BINARY_DIR}
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/config-tests/need_fslib.cxx)
|
||||
if(!need_fslib)
|
||||
# TODO: This may work for gcc 8, but some clang versions may need -lc++fs.
|
||||
link_libraries(stdc++fs)
|
||||
endif()
|
||||
|
||||
# check_cxx_source_compiles requires CMAKE_REQUIRED_DEFINITIONS to specify
|
||||
# compiling arguments.
|
||||
# Workaround: Pop CMAKE_REQUIRED_DEFINITIONS
|
||||
if(def)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS ${def})
|
||||
unset(def CACHE)
|
||||
else()
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS CACHE)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_QUIET OFF)
|
||||
|
||||
set(AC_CONFIG_H_IN "${PROJECT_SOURCE_DIR}/include/pqxx/config.h.in")
|
||||
set(CM_CONFIG_H_IN "${PROJECT_BINARY_DIR}/include/pqxx/config_cmake.h.in")
|
||||
set(CM_CONFIG_PUB "${PROJECT_BINARY_DIR}/include/pqxx/config-public-compiler.h")
|
||||
set(CM_CONFIG_INT "${PROJECT_BINARY_DIR}/include/pqxx/config-internal-compiler.h")
|
||||
set(CM_CONFIG_PQ "${PROJECT_BINARY_DIR}/include/pqxx/config-internal-libpq.h")
|
||||
message(STATUS "Generating config.h")
|
||||
file(WRITE "${CM_CONFIG_H_IN}" "")
|
||||
file(STRINGS "${AC_CONFIG_H_IN}" lines)
|
||||
foreach(line ${lines})
|
||||
string(REGEX REPLACE "^#undef" "#cmakedefine" l "${line}")
|
||||
file(APPEND "${CM_CONFIG_H_IN}" "${l}\n")
|
||||
endforeach()
|
||||
configure_file("${CM_CONFIG_H_IN}" "${CM_CONFIG_INT}" @ONLY)
|
||||
configure_file("${CM_CONFIG_H_IN}" "${CM_CONFIG_PUB}" @ONLY)
|
||||
configure_file("${CM_CONFIG_H_IN}" "${CM_CONFIG_PQ}" @ONLY)
|
||||
message(STATUS "Generating config.h - done")
|
4
ext/libpqxx-7.7.3/cmake/libpqxx-config.cmake
Normal file
4
ext/libpqxx-7.7.3/cmake/libpqxx-config.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(PostgreSQL)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/libpqxx-targets.cmake")
|
1
ext/libpqxx-7.7.3/compile_flags.in
Normal file
1
ext/libpqxx-7.7.3/compile_flags.in
Normal file
@ -0,0 +1 @@
|
||||
@CPPFLAGS@ @CXXFLAGS@
|
22
ext/libpqxx-7.7.3/config-tests/README.md
Normal file
22
ext/libpqxx-7.7.3/config-tests/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
Configuration tests
|
||||
===================
|
||||
|
||||
Libpqxx comes with support for different build systems: the GNU autotools,
|
||||
CMake, Visual Studio's "nmake", and raw GNU "make" on Windows.
|
||||
|
||||
For several of these build systems, we need to test things like "does this
|
||||
compiler environment support `std::to_chars` for floating-point types?"
|
||||
|
||||
We test these things by trying to compile a particular snippet of code, and
|
||||
seeing whether that succeeds.
|
||||
|
||||
To avoid duplicating those snippets for multiple build systems, we put them
|
||||
here. Both the autotools configuration and the CMake configuration can refer to
|
||||
them that way.
|
||||
|
||||
It took a bit of nasty magic to read a C++ source file into m4 and treat it as
|
||||
a string literal, without macro expansion. There is every chance that I missed
|
||||
something, so be prepared for tests failing for unexpected reasons! Some C++
|
||||
syntax may end up having an unforeseen meaning in m4, and screw up the handling
|
||||
of the code snippet. Re-configure, and read your logs carefully after editing
|
||||
these snippets.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user