summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
authorYossi Gottlieb <yossigo@gmail.com>2022-02-14 13:52:57 +0200
committerYossi Gottlieb <yossigo@gmail.com>2022-02-14 13:52:57 +0200
commit886a04c2c3899611b352e87070aa874e321f9034 (patch)
treed8f1723ffbe6b87c3f8c878f4759b4e0acd0c8f8 /deps
parente6478cfd10ae5ce8312c49823142d4dfcf0f45bb (diff)
parent418de21d8feb35303904ec718fcd1387e4699d2f (diff)
downloadredis-886a04c2c3899611b352e87070aa874e321f9034.tar.gz
Merge commit '418de21d8feb35303904ec718fcd1387e4699d2f' into refresh-hiredis
Diffstat (limited to 'deps')
-rw-r--r--deps/hiredis/.github/workflows/build.yml205
-rw-r--r--deps/hiredis/.travis.yml12
-rw-r--r--deps/hiredis/CHANGELOG.md19
-rw-r--r--deps/hiredis/CMakeLists.txt110
-rw-r--r--deps/hiredis/Makefile111
-rw-r--r--deps/hiredis/README.md41
-rw-r--r--deps/hiredis/adapters/libev.h27
-rw-r--r--deps/hiredis/adapters/libevent.h2
-rw-r--r--deps/hiredis/adapters/libuv.h162
-rw-r--r--deps/hiredis/async.c154
-rw-r--r--deps/hiredis/async.h2
-rw-r--r--deps/hiredis/dict.c11
-rw-r--r--deps/hiredis/dict.h3
-rw-r--r--deps/hiredis/examples/CMakeLists.txt2
-rw-r--r--deps/hiredis/examples/example-libuv.c37
-rw-r--r--deps/hiredis/examples/example-push.c1
-rw-r--r--deps/hiredis/examples/example-ssl.c5
-rw-r--r--deps/hiredis/examples/example.c5
-rw-r--r--deps/hiredis/fmacros.h2
-rw-r--r--deps/hiredis/fuzzing/format_command_fuzzer.c57
-rw-r--r--deps/hiredis/hiredis.c180
-rw-r--r--deps/hiredis/hiredis.h28
-rw-r--r--deps/hiredis/hiredis.targets11
-rw-r--r--deps/hiredis/hiredis_ssl.h4
-rw-r--r--deps/hiredis/net.c2
-rw-r--r--deps/hiredis/read.c166
-rw-r--r--deps/hiredis/sds.c826
-rw-r--r--deps/hiredis/sds.h262
-rw-r--r--deps/hiredis/sdsalloc.h6
-rw-r--r--deps/hiredis/sdscompat.h94
-rw-r--r--deps/hiredis/ssl.c47
-rw-r--r--deps/hiredis/test.c626
32 files changed, 2181 insertions, 1039 deletions
diff --git a/deps/hiredis/.github/workflows/build.yml b/deps/hiredis/.github/workflows/build.yml
new file mode 100644
index 000000000..362bc77b7
--- /dev/null
+++ b/deps/hiredis/.github/workflows/build.yml
@@ -0,0 +1,205 @@
+name: Build and test
+on: [push, pull_request]
+
+jobs:
+ ubuntu:
+ name: Ubuntu
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ repository: ${{ env.GITHUB_REPOSITORY }}
+ ref: ${{ env.GITHUB_HEAD_REF }}
+
+ - name: Install dependencies
+ run: |
+ sudo add-apt-repository -y ppa:chris-lea/redis-server
+ sudo apt-get update
+ sudo apt-get install -y redis-server valgrind libevent-dev
+
+ - name: Build using cmake
+ env:
+ EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON -DENABLE_ASYNC_TESTS:BOOL=ON
+ CFLAGS: -Werror
+ CXXFLAGS: -Werror
+ run: mkdir build-ubuntu && cd build-ubuntu && cmake ..
+
+ - name: Build using makefile
+ run: USE_SSL=1 TEST_ASYNC=1 make
+
+ - name: Run tests
+ env:
+ SKIPS_AS_FAILS: 1
+ TEST_SSL: 1
+ run: $GITHUB_WORKSPACE/test.sh
+
+ # - name: Run tests under valgrind
+ # env:
+ # SKIPS_AS_FAILS: 1
+ # TEST_PREFIX: valgrind --error-exitcode=99 --track-origins=yes --leak-check=full
+ # run: $GITHUB_WORKSPACE/test.sh
+
+ centos7:
+ name: CentOS 7
+ runs-on: ubuntu-latest
+ container: centos:7
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ repository: ${{ env.GITHUB_REPOSITORY }}
+ ref: ${{ env.GITHUB_HEAD_REF }}
+
+ - name: Install dependencies
+ run: |
+ yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
+ yum -y --enablerepo=remi install redis
+ yum -y install gcc gcc-c++ make openssl openssl-devel cmake3 valgrind libevent-devel
+
+ - name: Build using cmake
+ env:
+ EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON -DENABLE_ASYNC_TESTS:BOOL=ON
+ CFLAGS: -Werror
+ CXXFLAGS: -Werror
+ run: mkdir build-centos7 && cd build-centos7 && cmake3 ..
+
+ - name: Build using Makefile
+ run: USE_SSL=1 TEST_ASYNC=1 make
+
+ - name: Run tests
+ env:
+ SKIPS_AS_FAILS: 1
+ TEST_SSL: 1
+ run: $GITHUB_WORKSPACE/test.sh
+
+ - name: Run tests under valgrind
+ env:
+ SKIPS_AS_FAILS: 1
+ TEST_SSL: 1
+ TEST_PREFIX: valgrind --error-exitcode=99 --track-origins=yes --leak-check=full
+ run: $GITHUB_WORKSPACE/test.sh
+
+ centos8:
+ name: RockyLinux 8
+ runs-on: ubuntu-latest
+ container: rockylinux:8
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ repository: ${{ env.GITHUB_REPOSITORY }}
+ ref: ${{ env.GITHUB_HEAD_REF }}
+
+ - name: Install dependencies
+ run: |
+ dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
+ dnf -y module install redis:remi-6.0
+ dnf -y group install "Development Tools"
+ dnf -y install openssl-devel cmake valgrind libevent-devel
+
+ - name: Build using cmake
+ env:
+ EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON -DENABLE_ASYNC_TESTS:BOOL=ON
+ CFLAGS: -Werror
+ CXXFLAGS: -Werror
+ run: mkdir build-centos8 && cd build-centos8 && cmake ..
+
+ - name: Build using Makefile
+ run: USE_SSL=1 TEST_ASYNC=1 make
+
+ - name: Run tests
+ env:
+ SKIPS_AS_FAILS: 1
+ TEST_SSL: 1
+ run: $GITHUB_WORKSPACE/test.sh
+
+ - name: Run tests under valgrind
+ env:
+ SKIPS_AS_FAILS: 1
+ TEST_SSL: 1
+ TEST_PREFIX: valgrind --error-exitcode=99 --track-origins=yes --leak-check=full
+ run: $GITHUB_WORKSPACE/test.sh
+
+ freebsd:
+ runs-on: macos-10.15
+ name: FreeBSD
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ repository: ${{ env.GITHUB_REPOSITORY }}
+ ref: ${{ env.GITHUB_HEAD_REF }}
+
+ - name: Build in FreeBSD
+ uses: vmactions/freebsd-vm@v0.1.5
+ with:
+ prepare: pkg install -y gmake cmake
+ run: |
+ mkdir build && cd build && cmake .. && make && cd ..
+ gmake
+
+ macos:
+ name: macOS
+ runs-on: macos-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ repository: ${{ env.GITHUB_REPOSITORY }}
+ ref: ${{ env.GITHUB_HEAD_REF }}
+
+ - name: Install dependencies
+ run: |
+ brew install openssl redis
+
+ - name: Build hiredis
+ run: USE_SSL=1 make
+
+ - name: Run tests
+ env:
+ TEST_SSL: 1
+ run: $GITHUB_WORKSPACE/test.sh
+
+ windows:
+ name: Windows
+ runs-on: windows-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+ with:
+ repository: ${{ env.GITHUB_REPOSITORY }}
+ ref: ${{ env.GITHUB_HEAD_REF }}
+
+ - name: Install dependencies
+ run: |
+ choco install -y ninja memurai-developer
+
+ - uses: ilammy/msvc-dev-cmd@v1
+ - name: Build hiredis
+ run: |
+ mkdir build && cd build
+ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DENABLE_EXAMPLES=ON
+ ninja -v
+
+ - name: Run tests
+ run: |
+ ./build/hiredis-test.exe
+
+ - name: Setup cygwin
+ uses: egor-tensin/setup-cygwin@v3
+ with:
+ platform: x64
+ packages: make git gcc-core
+
+ - name: Build in cygwin
+ env:
+ HIREDIS_PATH: ${{ github.workspace }}
+ run: |
+ build_hiredis() {
+ cd $(cygpath -u $HIREDIS_PATH)
+ git clean -xfd
+ make
+ }
+ build_hiredis
+ shell: C:\tools\cygwin\bin\bash.exe --login --norc -eo pipefail -o igncr '{0}'
diff --git a/deps/hiredis/.travis.yml b/deps/hiredis/.travis.yml
index f9a9460ff..1e9b5569f 100644
--- a/deps/hiredis/.travis.yml
+++ b/deps/hiredis/.travis.yml
@@ -17,11 +17,11 @@ branches:
- /^release\/.*$/
install:
- - if [ "$BITS" == "64" ]; then
+ - if [ "$TRAVIS_COMPILER" != "mingw" ]; 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
+ fi;
before_script:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
@@ -33,8 +33,6 @@ before_script:
addons:
apt:
- sources:
- - sourceline: 'ppa:chris-lea/redis-server'
packages:
- libc6-dbg
- libc6-dev
@@ -46,17 +44,13 @@ addons:
- 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;
+ - EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON";
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
if [ "$BITS" == "32" ]; then
CFLAGS="-m32 -Werror";
diff --git a/deps/hiredis/CHANGELOG.md b/deps/hiredis/CHANGELOG.md
index 271f1fcf3..2a2bc314a 100644
--- a/deps/hiredis/CHANGELOG.md
+++ b/deps/hiredis/CHANGELOG.md
@@ -1,3 +1,22 @@
+## [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:
diff --git a/deps/hiredis/CMakeLists.txt b/deps/hiredis/CMakeLists.txt
index f86c9b70b..fe6720b28 100644
--- a/deps/hiredis/CMakeLists.txt
+++ b/deps/hiredis/CMakeLists.txt
@@ -1,10 +1,9 @@
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)
+OPTION(ENABLE_SSL_TESTS "Should we test SSL connections" OFF)
+OPTION(ENABLE_ASYNC_TESTS "Should we run all asynchronous API tests" OFF)
MACRO(getVersionBit name)
SET(VERSION_REGEX "^#define ${name} (.+)$")
@@ -20,7 +19,13 @@ getVersionBit(HIREDIS_SONAME)
SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}")
MESSAGE("Detected version: ${VERSION}")
-PROJECT(hiredis VERSION "${VERSION}")
+PROJECT(hiredis LANGUAGES "C" VERSION "${VERSION}")
+INCLUDE(GNUInstallDirs)
+
+# Hiredis requires C99
+SET(CMAKE_C_STANDARD 99)
+SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
+SET(CMAKE_DEBUG_POSTFIX d)
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
@@ -41,30 +46,84 @@ IF(WIN32)
ENDIF()
ADD_LIBRARY(hiredis SHARED ${hiredis_sources})
+ADD_LIBRARY(hiredis_static STATIC ${hiredis_sources})
+ADD_LIBRARY(hiredis::hiredis ALIAS hiredis)
+ADD_LIBRARY(hiredis::hiredis_static ALIAS hiredis_static)
SET_TARGET_PROPERTIES(hiredis
PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE
VERSION "${HIREDIS_SONAME}")
+SET_TARGET_PROPERTIES(hiredis_static
+ PROPERTIES COMPILE_PDB_NAME hiredis_static)
+SET_TARGET_PROPERTIES(hiredis_static
+ PROPERTIES COMPILE_PDB_NAME_DEBUG hiredis_static${CMAKE_DEBUG_POSTFIX})
IF(WIN32 OR MINGW)
- TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32)
+ TARGET_LINK_LIBRARIES(hiredis PUBLIC ws2_32 crypt32)
+ TARGET_LINK_LIBRARIES(hiredis_static PUBLIC ws2_32 crypt32)
+ELSEIF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ TARGET_LINK_LIBRARIES(hiredis PUBLIC m)
+ TARGET_LINK_LIBRARIES(hiredis_static PUBLIC m)
+ELSEIF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
+ TARGET_LINK_LIBRARIES(hiredis PUBLIC socket)
+ TARGET_LINK_LIBRARIES(hiredis_static PUBLIC socket)
ENDIF()
-TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:.> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
+TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
+TARGET_INCLUDE_DIRECTORIES(hiredis_static PUBLIC $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY)
-INSTALL(TARGETS hiredis
+set(CPACK_PACKAGE_VENDOR "Redis")
+set(CPACK_PACKAGE_DESCRIPTION "\
+Hiredis is a minimalistic C client library for the Redis 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.")
+set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/redis/hiredis")
+set(CPACK_PACKAGE_CONTACT "michael dot grunder at gmail dot com")
+set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
+set(CPACK_RPM_PACKAGE_AUTOREQPROV ON)
+
+include(CPack)
+
+INSTALL(TARGETS hiredis hiredis_static
EXPORT hiredis-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+if (MSVC)
+ INSTALL(FILES $<TARGET_PDB_FILE:hiredis>
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
+ CONFIGURATIONS Debug RelWithDebInfo)
+ INSTALL(FILES $<TARGET_FILE_DIR:hiredis_static>/$<TARGET_FILE_BASE_NAME:hiredis_static>.pdb
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ CONFIGURATIONS Debug RelWithDebInfo)
+endif()
+
+# For NuGet packages
+INSTALL(FILES hiredis.targets
+ DESTINATION build/native)
+
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)
@@ -95,10 +154,12 @@ IF(ENABLE_SSL)
ENDIF()
ENDIF()
FIND_PACKAGE(OpenSSL REQUIRED)
- SET(hiredis_ssl_sources
+ SET(hiredis_ssl_sources
ssl.c)
ADD_LIBRARY(hiredis_ssl SHARED
${hiredis_ssl_sources})
+ ADD_LIBRARY(hiredis_ssl_static STATIC
+ ${hiredis_ssl_sources})
IF (APPLE)
SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup")
@@ -108,23 +169,39 @@ IF(ENABLE_SSL)
PROPERTIES
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
VERSION "${HIREDIS_SONAME}")
+ SET_TARGET_PROPERTIES(hiredis_ssl_static
+ PROPERTIES COMPILE_PDB_NAME hiredis_ssl_static)
+ SET_TARGET_PROPERTIES(hiredis_ssl_static
+ PROPERTIES COMPILE_PDB_NAME_DEBUG hiredis_ssl_static${CMAKE_DEBUG_POSTFIX})
TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}")
+ TARGET_INCLUDE_DIRECTORIES(hiredis_ssl_static PRIVATE "${OPENSSL_INCLUDE_DIR}")
+
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES})
IF (WIN32 OR MINGW)
TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis)
+ TARGET_LINK_LIBRARIES(hiredis_ssl_static PUBLIC hiredis_static)
ENDIF()
CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY)
- INSTALL(TARGETS hiredis_ssl
+ INSTALL(TARGETS hiredis_ssl hiredis_ssl_static
EXPORT hiredis_ssl-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ if (MSVC)
+ INSTALL(FILES $<TARGET_PDB_FILE:hiredis_ssl>
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
+ CONFIGURATIONS Debug RelWithDebInfo)
+ INSTALL(FILES $<TARGET_FILE_DIR:hiredis_ssl_static>/$<TARGET_FILE_BASE_NAME:hiredis_ssl_static>.pdb
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ CONFIGURATIONS Debug RelWithDebInfo)
+ endif()
+
INSTALL(FILES hiredis_ssl.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
-
+
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
@@ -149,11 +226,14 @@ ENDIF()
IF(NOT DISABLE_TESTS)
ENABLE_TESTING()
ADD_EXECUTABLE(hiredis-test test.c)
+ TARGET_LINK_LIBRARIES(hiredis-test hiredis)
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)
+ TARGET_LINK_LIBRARIES(hiredis-test hiredis_ssl)
+ ENDIF()
+ IF(ENABLE_ASYNC_TESTS)
+ ADD_DEFINITIONS(-DHIREDIS_TEST_ASYNC=1)
+ TARGET_LINK_LIBRARIES(hiredis-test event)
ENDIF()
ADD_TEST(NAME hiredis-test
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
diff --git a/deps/hiredis/Makefile b/deps/hiredis/Makefile
index 7e41c97a5..a2ad84c6b 100644
--- a/deps/hiredis/Makefile
+++ b/deps/hiredis/Makefile
@@ -4,16 +4,10 @@
# 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}')
@@ -60,33 +54,66 @@ DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=$(AR) rcs
+#################### SSL variables start ####################
+SSL_OBJ=ssl.o
+SSL_LIBNAME=libhiredis_ssl
+SSL_PKGCONFNAME=hiredis_ssl.pc
+SSL_INSTALLNAME=install-ssl
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)
+USE_SSL?=0
+ifeq ($(USE_SSL),1)
+ # This is required for test.c only
+ CFLAGS+=-DHIREDIS_TEST_SSL
+ EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
+ SSL_STLIB=$(SSL_STLIBNAME)
+ SSL_DYLIB=$(SSL_DYLIBNAME)
+ SSL_PKGCONF=$(SSL_PKGCONFNAME)
+ SSL_INSTALL=$(SSL_INSTALLNAME)
+else
+ SSL_STLIB=
+ SSL_DYLIB=
+ SSL_PKGCONF=
+ SSL_INSTALL=
+endif
+##################### SSL variables end #####################
+
+
# 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
+ifeq ($(TEST_ASYNC),1)
+ export CFLAGS+=-DHIREDIS_TEST_ASYNC
endif
-ifeq ($(uname_S),Linux)
- ifdef OPENSSL_PREFIX
+ifeq ($(USE_SSL),1)
+ ifeq ($(uname_S),Linux)
+ ifdef OPENSSL_PREFIX
+ CFLAGS+=-I$(OPENSSL_PREFIX)/include
+ SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
+ else
+ SSL_LDFLAGS=-lssl -lcrypto
+ endif
+ else
+ OPENSSL_PREFIX?=/usr/local/opt/openssl
CFLAGS+=-I$(OPENSSL_PREFIX)/include
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
- else
- SSL_LDFLAGS=-lssl -lcrypto
+ endif
+endif
+
+ifeq ($(uname_S),FreeBSD)
+ LDFLAGS+=-lm
+ IS_GCC=$(shell sh -c '$(CC) --version 2>/dev/null |egrep -i -c "gcc"')
+ ifeq ($(IS_GCC),1)
+ REAL_CFLAGS+=-pedantic
endif
else
- OPENSSL_PREFIX?=/usr/local/opt/openssl
- CFLAGS+=-I$(OPENSSL_PREFIX)/include
- SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
+ REAL_CFLAGS+=-pedantic
endif
ifeq ($(uname_S),SunOS)
@@ -108,10 +135,13 @@ ifeq ($(uname_S),Darwin)
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
+all: dynamic static hiredis-test pkgconfig
+
+dynamic: $(DYLIBNAME) $(SSL_DYLIB)
+
+static: $(STLIBNAME) $(SSL_STLIB)
+
+pkgconfig: $(PKGCONFNAME) $(SSL_PKGCONF)
# Deps (use make dep to generate this)
alloc.o: alloc.c fmacros.h alloc.h
@@ -122,7 +152,6 @@ 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)
@@ -131,18 +160,15 @@ $(DYLIBNAME): $(OBJ)
$(STLIBNAME): $(OBJ)
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)
+#################### SSL building rules start ####################
$(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
+$(SSL_OBJ): ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h
+#################### SSL building rules end ####################
# Binaries:
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
@@ -166,7 +192,6 @@ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
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)"
@@ -177,10 +202,11 @@ hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME)
endif
ifndef LIBUV_DIR
-hiredis-example-libuv:
- @echo "Please specify LIBUV_DIR (e.g. ../libuv/)"
- @false
+# dynamic link libuv.so
+hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
+ $(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< -luv -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS)
else
+# use user provided static lib
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
@@ -206,10 +232,13 @@ hiredis-example-push: examples/example-push.c $(STLIBNAME)
examples: $(EXAMPLES)
-TEST_LIBS = $(STLIBNAME)
+TEST_LIBS = $(STLIBNAME) $(SSL_STLIB)
+TEST_LDFLAGS = $(SSL_LDFLAGS)
ifeq ($(USE_SSL),1)
- TEST_LIBS += $(SSL_STLIBNAME)
- TEST_LDFLAGS = $(SSL_LDFLAGS) -lssl -lcrypto -lpthread
+ TEST_LDFLAGS += -pthread
+endif
+ifeq ($(TEST_ASYNC),1)
+ TEST_LDFLAGS += -levent
endif
hiredis-test: test.o $(TEST_LIBS)
@@ -225,7 +254,7 @@ check: hiredis-test
TEST_SSL=$(USE_SSL) ./test.sh
.c.o:
- $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<
+ $(CC) -std=c99 -c $(REAL_CFLAGS) $<
clean:
rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
@@ -262,7 +291,7 @@ $(SSL_PKGCONFNAME): hiredis_ssl.h
@echo Libs: -L\$${libdir} -lhiredis_ssl >> $@
@echo Libs.private: -lssl -lcrypto >> $@
-install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
+install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) $(SSL_INSTALL)
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
@@ -272,9 +301,6 @@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
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)
@@ -283,7 +309,6 @@ install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
$(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH)
mkdir -p $(INSTALL_PKGCONF_PATH)
$(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
-endif
32bit:
@echo ""
@@ -299,12 +324,12 @@ gprof:
$(MAKE) CFLAGS="-pg" LDFLAGS="-pg"
gcov:
- $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs"
+ $(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
+ lcov -d . -c --exclude '/usr*' -o tmp/lcov/hiredis.info
genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info
noopt:
diff --git a/deps/hiredis/README.md b/deps/hiredis/README.md
index 3a22553ea..ed66220c7 100644
--- a/deps/hiredis/README.md
+++ b/deps/hiredis/README.md
@@ -1,10 +1,11 @@
-[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)
+
+[![Build Status](https://github.com/redis/hiredis/actions/workflows/build.yml/badge.svg)](https://github.com/redis/hiredis/actions/workflows/build.yml)
**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.
+Hiredis is a minimalistic C client library for the [Redis](https://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
@@ -22,6 +23,12 @@ 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.
@@ -169,7 +176,7 @@ Hiredis also supports every new `RESP3` data type which are as follows. For mor
* **`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.
+ The MAP is functionally equivalent to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.
* **`REDIS_REPLY_SET`**:
* An array response where each entry is unique.
@@ -189,7 +196,7 @@ Hiredis also supports every new `RESP3` data type which are as follows. For mor
* **`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).
+ The string payload is stored in the `str` member, 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
@@ -261,9 +268,9 @@ a single call to `read(2)`):
redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
-redisGetReply(context,(void *)&reply); // reply for SET
+redisGetReply(context,(void**)&reply); // reply for SET
freeReplyObject(reply);
-redisGetReply(context,(void *)&reply); // reply for GET
+redisGetReply(context,(void**)&reply); // reply for GET
freeReplyObject(reply);
```
This API can also be used to implement a blocking subscriber:
@@ -517,7 +524,7 @@ initialize OpenSSL and create a context. You can do that in two ways:
/* An Hiredis SSL context. It holds SSL configuration and can be reused across
* many contexts.
*/
-redisSSLContext *ssl;
+redisSSLContext *ssl_context;
/* An error variable to indicate what went wrong, if the context fails to
* initialize.
@@ -532,17 +539,23 @@ redisSSLContextError ssl_error;
redisInitOpenSSL();
/* Create SSL context */
-ssl = redisCreateSSLContext(
+ssl_context = 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... */
- }
+ &ssl_error);
+
+if(ssl_context == NULL || ssl_error != 0) {
+ /* Handle error and abort... */
+ /* e.g.
+ printf("SSL error: %s\n",
+ (ssl_error != 0) ?
+ redisSSLContextGetError(ssl_error) : "Unknown error");
+ // Abort
+ */
+}
/* Create Redis context and establish connection */
c = redisConnect("localhost", 6443);
@@ -551,7 +564,7 @@ if (c == NULL || c->err) {
}
/* Negotiate SSL/TLS */
-if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) {
+if (redisInitiateSSLWithContext(c, ssl_context) != REDIS_OK) {
/* Handle error, in c->err / c->errstr */
}
```
diff --git a/deps/hiredis/adapters/libev.h b/deps/hiredis/adapters/libev.h
index e1e7bbd99..c59d3da77 100644
--- a/deps/hiredis/adapters/libev.h
+++ b/deps/hiredis/adapters/libev.h
@@ -46,7 +46,7 @@ typedef struct redisLibevEvents {
static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
#if EV_MULTIPLICITY
- ((void)loop);
+ ((void)EV_A);
#endif
((void)revents);
@@ -56,7 +56,7 @@ static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
#if EV_MULTIPLICITY
- ((void)loop);
+ ((void)EV_A);
#endif
((void)revents);
@@ -66,8 +66,9 @@ static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
static void redisLibevAddRead(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
+#if EV_MULTIPLICITY
struct ev_loop *loop = e->loop;
- ((void)loop);
+#endif
if (!e->reading) {
e->reading = 1;
ev_io_start(EV_A_ &e->rev);
@@ -76,8 +77,9 @@ static void redisLibevAddRead(void *privdata) {
static void redisLibevDelRead(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
+#if EV_MULTIPLICITY
struct ev_loop *loop = e->loop;
- ((void)loop);
+#endif
if (e->reading) {
e->reading = 0;
ev_io_stop(EV_A_ &e->rev);
@@ -86,8 +88,9 @@ static void redisLibevDelRead(void *privdata) {
static void redisLibevAddWrite(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
+#if EV_MULTIPLICITY
struct ev_loop *loop = e->loop;
- ((void)loop);
+#endif
if (!e->writing) {
e->writing = 1;
ev_io_start(EV_A_ &e->wev);
@@ -96,8 +99,9 @@ static void redisLibevAddWrite(void *privdata) {
static void redisLibevDelWrite(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
+#if EV_MULTIPLICITY
struct ev_loop *loop = e->loop;
- ((void)loop);
+#endif
if (e->writing) {
e->writing = 0;
ev_io_stop(EV_A_ &e->wev);
@@ -106,8 +110,9 @@ static void redisLibevDelWrite(void *privdata) {
static void redisLibevStopTimer(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
+#if EV_MULTIPLICITY
struct ev_loop *loop = e->loop;
- ((void)loop);
+#endif
ev_timer_stop(EV_A_ &e->timer);
}
@@ -120,6 +125,9 @@ static void redisLibevCleanup(void *privdata) {
}
static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) {
+#if EV_MULTIPLICITY
+ ((void)EV_A);
+#endif
((void)revents);
redisLibevEvents *e = (redisLibevEvents*)timer->data;
redisAsyncHandleTimeout(e->context);
@@ -127,8 +135,9 @@ static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) {
static void redisLibevSetTimeout(void *privdata, struct timeval tv) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
+#if EV_MULTIPLICITY
struct ev_loop *loop = e->loop;
- ((void)loop);
+#endif
if (!ev_is_active(&e->timer)) {
ev_init(&e->timer, redisLibevTimeout);
@@ -154,7 +163,7 @@ static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
e->context = ac;
#if EV_MULTIPLICITY
- e->loop = loop;
+ e->loop = EV_A;
#else
e->loop = NULL;
#endif
diff --git a/deps/hiredis/adapters/libevent.h b/deps/hiredis/adapters/libevent.h
index 9150979bc..73bb8ed75 100644
--- a/deps/hiredis/adapters/libevent.h
+++ b/deps/hiredis/adapters/libevent.h
@@ -50,7 +50,7 @@ static void redisLibeventDestroy(redisLibeventEvents *e) {
hi_free(e);
}
-static void redisLibeventHandler(int fd, short event, void *arg) {
+static void redisLibeventHandler(evutil_socket_t fd, short event, void *arg) {
((void)fd);
redisLibeventEvents *e = (redisLibeventEvents*)arg;
e->state |= REDIS_LIBEVENT_ENTERED;
diff --git a/deps/hiredis/adapters/libuv.h b/deps/hiredis/adapters/libuv.h
index c120b1b39..df0a84578 100644
--- a/deps/hiredis/adapters/libuv.h
+++ b/deps/hiredis/adapters/libuv.h
@@ -7,111 +7,157 @@
#include <string.h>
typedef struct redisLibuvEvents {
- redisAsyncContext* context;
- uv_poll_t handle;
- int events;
+ redisAsyncContext* context;
+ uv_poll_t handle;
+ uv_timer_t timer;
+ 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);
- }
+ 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;
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
- p->events |= UV_READABLE;
+ p->events |= UV_READABLE;
- uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
}
static void redisLibuvDelRead(void *privdata) {
- redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
- p->events &= ~UV_READABLE;
+ p->events &= ~UV_READABLE;
- if (p->events) {
- uv_poll_start(&p->handle, p->events, redisLibuvPoll);
- } else {
- uv_poll_stop(&p->handle);
- }
+ 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;
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
- p->events |= UV_WRITABLE;
+ p->events |= UV_WRITABLE;
- uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
}
static void redisLibuvDelWrite(void *privdata) {
- redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
- p->events &= ~UV_WRITABLE;
+ p->events &= ~UV_WRITABLE;
- if (p->events) {
- uv_poll_start(&p->handle, p->events, redisLibuvPoll);
- } else {
- uv_poll_stop(&p->handle);
- }
+ if (p->events) {
+ uv_poll_start(&p->handle, p->events, redisLibuvPoll);
+ } else {
+ uv_poll_stop(&p->handle);
+ }
}
+static void on_timer_close(uv_handle_t *handle) {
+ redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
+ p->timer.data = NULL;
+ if (!p->handle.data) {
+ // both timer and handle are closed
+ hi_free(p);
+ }
+ // else, wait for `on_handle_close`
+}
-static void on_close(uv_handle_t* handle) {
- redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
+static void on_handle_close(uv_handle_t *handle) {
+ redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
+ p->handle.data = NULL;
+ if (!p->timer.data) {
+ // timer never started, or timer already destroyed
+ hi_free(p);
+ }
+ // else, wait for `on_timer_close`
+}
- hi_free(p);
+// libuv removed `status` parameter since v0.11.23
+// see: https://github.com/libuv/libuv/blob/v0.11.23/include/uv.h
+#if (UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR < 11) || \
+ (UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR == 11 && UV_VERSION_PATCH < 23)
+static void redisLibuvTimeout(uv_timer_t *timer, int status) {
+ (void)status; // unused
+#else
+static void redisLibuvTimeout(uv_timer_t *timer) {
+#endif
+ redisLibuvEvents *e = (redisLibuvEvents*)timer->data;
+ redisAsyncHandleTimeout(e->context);
}
+static void redisLibuvSetTimeout(void *privdata, struct timeval tv) {
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+
+ uint64_t millsec = tv.tv_sec * 1000 + tv.tv_usec / 1000.0;
+ if (!p->timer.data) {
+ // timer is uninitialized
+ if (uv_timer_init(p->handle.loop, &p->timer) != 0) {
+ return;
+ }
+ p->timer.data = p;
+ }
+ // updates the timeout if the timer has already started
+ // or start the timer
+ uv_timer_start(&p->timer, redisLibuvTimeout, millsec, 0);
+}
static void redisLibuvCleanup(void *privdata) {
- redisLibuvEvents* p = (redisLibuvEvents*)privdata;
+ redisLibuvEvents* p = (redisLibuvEvents*)privdata;
- p->context = NULL; // indicate that context might no longer exist
- uv_close((uv_handle_t*)&p->handle, on_close);
+ p->context = NULL; // indicate that context might no longer exist
+ if (p->timer.data) {
+ uv_close((uv_handle_t*)&p->timer, on_timer_close);
+ }
+ uv_close((uv_handle_t*)&p->handle, on_handle_close);
}
static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
- redisContext *c = &(ac->c);
+ redisContext *c = &(ac->c);
- if (ac->ev.data != NULL) {
- return REDIS_ERR;
- }
+ 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;
+ ac->ev.addRead = redisLibuvAddRead;
+ ac->ev.delRead = redisLibuvDelRead;
+ ac->ev.addWrite = redisLibuvAddWrite;
+ ac->ev.delWrite = redisLibuvDelWrite;
+ ac->ev.cleanup = redisLibuvCleanup;
+ ac->ev.scheduleTimer = redisLibuvSetTimeout;
- redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p));
- if (p == NULL)
- return REDIS_ERR;
+ redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p));
+ if (p == NULL)
+ return REDIS_ERR;
- memset(p, 0, sizeof(*p));
+ memset(p, 0, sizeof(*p));
- if (uv_poll_init_socket(loop, &p->handle, c->fd) != 0) {
- return REDIS_ERR;
- }
+ 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;
+ ac->ev.data = p;
+ p->handle.data = p;
+ p->context = ac;
- return REDIS_OK;
+ return REDIS_OK;
}
#endif
diff --git a/deps/hiredis/async.c b/deps/hiredis/async.c
index 64ab601c9..65551142b 100644
--- a/deps/hiredis/async.c
+++ b/deps/hiredis/async.c
@@ -47,6 +47,11 @@
#include "async_private.h"
+#ifdef NDEBUG
+#undef assert
+#define assert(e) (void)(e)
+#endif
+
/* 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);
@@ -54,7 +59,7 @@ 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,
- hi_sdslen((const hisds)key));
+ sdslen((const sds)key));
}
static void *callbackValDup(void *privdata, const void *src) {
@@ -73,15 +78,15 @@ static int callbackKeyCompare(void *privdata, const void *key1, const void *key2
int l1, l2;
((void) privdata);
- l1 = hi_sdslen((const hisds)key1);
- l2 = hi_sdslen((const hisds)key2);
+ 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);
- hi_sdsfree((hisds)key);
+ sdsfree((sds)key);
}
static void callbackValDestructor(void *privdata, void *val) {
@@ -139,8 +144,8 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
ac->replies.head = NULL;
ac->replies.tail = NULL;
- ac->sub.invalid.head = NULL;
- ac->sub.invalid.tail = NULL;
+ ac->sub.replies.head = NULL;
+ ac->sub.replies.tail = NULL;
ac->sub.channels = channels;
ac->sub.patterns = patterns;
@@ -301,36 +306,28 @@ static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) {
static void __redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb;
- dictIterator *it;
+ 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)
+ while (__redisShiftCallback(&ac->sub.replies,&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);
- }
+ dictInitIterator(&it,ac->sub.channels);
+ while ((de = dictNext(&it)) != NULL)
+ __redisRunCallback(ac,dictGetEntryVal(de),NULL);
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);
- }
+ dictInitIterator(&it,ac->sub.patterns);
+ while ((de = dictNext(&it)) != NULL)
+ __redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictRelease(ac->sub.patterns);
}
@@ -418,12 +415,13 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
dictEntry *de;
int pvariant;
char *stype;
- hisds sname;
+ 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);
+ /* Match reply with the expected format of a pushed message.
+ * The type and number of elements (3 to 4) are specified at:
+ * https://redis.io/topics/pubsub#format-of-pushed-messages */
+ if ((reply->type == REDIS_REPLY_ARRAY && !(c->flags & REDIS_SUPPORTS_PUSH) && reply->elements >= 3) ||
+ reply->type == REDIS_REPLY_PUSH) {
assert(reply->element[0]->type == REDIS_REPLY_STRING);
stype = reply->element[0]->str;
pvariant = (tolower(stype[0]) == 'p') ? 1 : 0;
@@ -435,7 +433,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
/* Locate the right callback */
assert(reply->element[1]->type == REDIS_REPLY_STRING);
- sname = hi_sdsnewlen(reply->element[1]->str,reply->element[1]->len);
+ sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
if (sname == NULL)
goto oom;
@@ -462,14 +460,21 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
/* 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)
+ && dictSize(ac->sub.patterns) == 0) {
c->flags &= ~REDIS_SUBSCRIBED;
+
+ /* Move ongoing regular command callbacks. */
+ redisCallback cb;
+ while (__redisShiftCallback(&ac->sub.replies,&cb) == REDIS_OK) {
+ __redisPushCallback(&ac->replies,&cb);
+ }
+ }
}
}
- hi_sdsfree(sname);
+ sdsfree(sname);
} else {
- /* Shift callback for invalid commands. */
- __redisShiftCallback(&ac->sub.invalid,dstcb);
+ /* Shift callback for pending command in subscribed context. */
+ __redisShiftCallback(&ac->sub.replies,dstcb);
}
return REDIS_OK;
oom:
@@ -497,13 +502,12 @@ static int redisIsSubscribeReply(redisReply *reply) {
len = reply->element[0]->len - off;
return !strncasecmp(str, "subscribe", len) ||
- !strncasecmp(str, "message", len);
-
+ !strncasecmp(str, "message", len) ||
+ !strncasecmp(str, "unsubscribe", len);
}
void redisProcessCallbacks(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
- redisCallback cb = {NULL, NULL, 0, NULL};
void *reply = NULL;
int status;
@@ -511,22 +515,19 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
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 && hi_sdslen(c->obuf) == 0
+ 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;
}
+ /* Keep track of push message support for subscribe handling */
+ if (redisIsPushReply(reply)) c->flags |= REDIS_SUPPORTS_PUSH;
+
/* 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
@@ -539,6 +540,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
/* Even if the context is subscribed, pending regular
* callbacks will get a reply before pub/sub messages arrive. */
+ redisCallback cb = {NULL, NULL, 0, NULL};
if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
/*
* A spontaneous reply in a not-subscribed context can be the error
@@ -562,15 +564,17 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
__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)
+ /* No more regular callbacks and no errors, the context *must* be subscribed. */
+ assert(c->flags & REDIS_SUBSCRIBED);
+ if (c->flags & REDIS_SUBSCRIBED)
__redisGetSubscribeCallback(ac,reply,&cb);
}
if (cb.fn != NULL) {
__redisRunCallback(ac,&cb,reply);
- c->reader->fn->freeObject(reply);
+ if (!(c->flags & REDIS_NO_AUTO_FREE_REPLIES)){
+ c->reader->fn->freeObject(reply);
+ }
/* Proceed with free'ing when redisAsyncFree() was called. */
if (c->flags & REDIS_FREEING) {
@@ -584,6 +588,11 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
* doesn't know what the server will spit out over the wire. */
c->reader->fn->freeObject(reply);
}
+
+ /* If in monitor mode, repush the callback */
+ if (c->flags & REDIS_MONITORING) {
+ __redisPushCallback(&ac->replies,&cb);
+ }
}
/* Disconnect when there was an error reading the reply */
@@ -605,7 +614,8 @@ static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
if (redisCheckConnectDone(c, &completed) == REDIS_ERR) {
/* Error! */
- redisCheckSocketError(c);
+ if (redisCheckSocketError(c) == REDIS_ERR)
+ __redisAsyncCopyError(ac);
__redisAsyncHandleConnectFailure(ac);
return REDIS_ERR;
} else if (completed == 1) {
@@ -691,13 +701,22 @@ 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->flags & REDIS_CONNECTED)) {
+ if (ac->replies.head == NULL && ac->sub.replies.head == NULL) {
+ /* Nothing to do - just an idle timeout */
+ return;
+ }
+
+ if (!ac->c.command_timeout ||
+ (!ac->c.command_timeout->tv_sec && !ac->c.command_timeout->tv_usec)) {
+ /* A belated connect timeout arriving, ignore */
+ return;
+ }
}
if (!c->err) {
__redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout");
+ __redisAsyncCopyError(ac);
}
if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) {
@@ -744,7 +763,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
const char *cstr, *astr;
size_t clen, alen;
const char *p;
- hisds sname;
+ sds sname;
int ret;
/* Don't accept new commands when the connection is about to be closed. */
@@ -768,7 +787,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
/* Add every channel/pattern to the list of subscription callbacks. */
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
- sname = hi_sdsnewlen(astr,alen);
+ sname = sdsnewlen(astr,alen);
if (sname == NULL)
goto oom;
@@ -786,7 +805,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
ret = dictReplace(cbdict,sname,&cb);
- if (ret == 0) hi_sdsfree(sname);
+ 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
@@ -796,17 +815,19 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
/* (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 (strncasecmp(cstr,"monitor\r\n",9) == 0) {
+ /* Set monitor flag and push callback */
+ c->flags |= REDIS_MONITORING;
+ if (__redisPushCallback(&ac->replies,&cb) != REDIS_OK)
+ goto oom;
} 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);
+ if (c->flags & REDIS_SUBSCRIBED) {
+ if (__redisPushCallback(&ac->sub.replies,&cb) != REDIS_OK)
+ goto oom;
+ } else {
+ if (__redisPushCallback(&ac->replies,&cb) != REDIS_OK)
+ goto oom;
+ }
}
__redisAppendCommand(c,cmd,len);
@@ -817,6 +838,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
return REDIS_OK;
oom:
__redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory");
+ __redisAsyncCopyError(ac);
return REDIS_ERR;
}
@@ -845,14 +867,14 @@ int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata
}
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
- hisds cmd;
- int len;
+ sds cmd;
+ long long len;
int status;
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
if (len < 0)
return REDIS_ERR;
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
- hi_sdsfree(cmd);
+ sdsfree(cmd);
return status;
}
diff --git a/deps/hiredis/async.h b/deps/hiredis/async.h
index b1d2cb263..4c65203c1 100644
--- a/deps/hiredis/async.h
+++ b/deps/hiredis/async.h
@@ -102,7 +102,7 @@ typedef struct redisAsyncContext {
/* Subscription callbacks */
struct {
- redisCallbackList invalid;
+ redisCallbackList replies;
struct dict *channels;
struct dict *patterns;
} sub;
diff --git a/deps/hiredis/dict.c b/deps/hiredis/dict.c
index 34a33ead9..ad571818e 100644
--- a/deps/hiredis/dict.c
+++ b/deps/hiredis/dict.c
@@ -267,16 +267,11 @@ static dictEntry *dictFind(dict *ht, const void *key) {
return NULL;
}
-static dictIterator *dictGetIterator(dict *ht) {
- dictIterator *iter = hi_malloc(sizeof(*iter));
- if (iter == NULL)
- return NULL;
-
+static void dictInitIterator(dictIterator *iter, dict *ht) {
iter->ht = ht;
iter->index = -1;
iter->entry = NULL;
iter->nextEntry = NULL;
- return iter;
}
static dictEntry *dictNext(dictIterator *iter) {
@@ -299,10 +294,6 @@ static dictEntry *dictNext(dictIterator *iter) {
return NULL;
}
-static void dictReleaseIterator(dictIterator *iter) {
- hi_free(iter);
-}
-
/* ------------------------- private functions ------------------------------ */
/* Expand the hash table if needed */
diff --git a/deps/hiredis/dict.h b/deps/hiredis/dict.h
index 95fcd280e..6ad0acd8d 100644
--- a/deps/hiredis/dict.h
+++ b/deps/hiredis/dict.h
@@ -119,8 +119,7 @@ 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 void dictInitIterator(dictIterator *iter, dict *ht);
static dictEntry *dictNext(dictIterator *iter);
-static void dictReleaseIterator(dictIterator *iter);
#endif /* __DICT_H */
diff --git a/deps/hiredis/examples/CMakeLists.txt b/deps/hiredis/examples/CMakeLists.txt
index 1d5bc56e0..49cd8d440 100644
--- a/deps/hiredis/examples/CMakeLists.txt
+++ b/deps/hiredis/examples/CMakeLists.txt
@@ -21,7 +21,7 @@ ENDIF()
FIND_PATH(LIBEVENT event.h)
if (LIBEVENT)
- ADD_EXECUTABLE(example-libevent example-libevent)
+ ADD_EXECUTABLE(example-libevent example-libevent.c)
TARGET_LINK_LIBRARIES(example-libevent hiredis event)
ENDIF()
diff --git a/deps/hiredis/examples/example-libuv.c b/deps/hiredis/examples/example-libuv.c
index cbde452b9..53fd04a8e 100644
--- a/deps/hiredis/examples/example-libuv.c
+++ b/deps/hiredis/examples/example-libuv.c
@@ -7,18 +7,33 @@
#include <async.h>
#include <adapters/libuv.h>
+void debugCallback(redisAsyncContext *c, void *r, void *privdata) {
+ (void)privdata; //unused
+ redisReply *reply = r;
+ if (reply == NULL) {
+ /* The DEBUG SLEEP command will almost always fail, because we have set a 1 second timeout */
+ printf("`DEBUG SLEEP` error: %s\n", c->errstr ? c->errstr : "unknown error");
+ return;
+ }
+ /* Disconnect after receiving the reply of DEBUG SLEEP (which will not)*/
+ redisAsyncDisconnect(c);
+}
+
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
- if (reply == NULL) return;
- printf("argv[%s]: %s\n", (char*)privdata, reply->str);
+ if (reply == NULL) {
+ printf("`GET key` error: %s\n", c->errstr ? c->errstr : "unknown error");
+ return;
+ }
+ printf("`GET key` result: argv[%s]: %s\n", (char*)privdata, reply->str);
- /* Disconnect after receiving the reply to GET */
- redisAsyncDisconnect(c);
+ /* start another request that demonstrate timeout */
+ redisAsyncCommand(c, debugCallback, NULL, "DEBUG SLEEP %f", 1.5);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
- printf("Error: %s\n", c->errstr);
+ printf("connect error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
@@ -26,7 +41,7 @@ void connectCallback(const redisAsyncContext *c, int status) {
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
- printf("Error: %s\n", c->errstr);
+ printf("disconnect because of error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
@@ -49,8 +64,18 @@ int main (int argc, char **argv) {
redisLibuvAttach(c,loop);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
+ redisAsyncSetTimeout(c, (struct timeval){ .tv_sec = 1, .tv_usec = 0});
+
+ /*
+ In this demo, we first `set key`, then `get key` to demonstrate the basic usage of libuv adapter.
+ Then in `getCallback`, we start a `debug sleep` command to create 1.5 second long request.
+ Because we have set a 1 second timeout to the connection, the command will always fail with a
+ timeout error, which is shown in the `debugCallback`.
+ */
+
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;
}
diff --git a/deps/hiredis/examples/example-push.c b/deps/hiredis/examples/example-push.c
index 2d4ab4dc0..6bc12055e 100644
--- a/deps/hiredis/examples/example-push.c
+++ b/deps/hiredis/examples/example-push.c
@@ -31,7 +31,6 @@
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
-#include <win32.h>
#define KEY_COUNT 5
diff --git a/deps/hiredis/examples/example-ssl.c b/deps/hiredis/examples/example-ssl.c
index c754177cf..b8ca44281 100644
--- a/deps/hiredis/examples/example-ssl.c
+++ b/deps/hiredis/examples/example-ssl.c
@@ -4,7 +4,10 @@
#include <hiredis.h>
#include <hiredis_ssl.h>
-#include <win32.h>
+
+#ifdef _MSC_VER
+#include <winsock2.h> /* For struct timeval */
+#endif
int main(int argc, char **argv) {
unsigned int j;
diff --git a/deps/hiredis/examples/example.c b/deps/hiredis/examples/example.c
index 15dacbd18..f1b8b4a85 100644
--- a/deps/hiredis/examples/example.c
+++ b/deps/hiredis/examples/example.c
@@ -2,7 +2,10 @@
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
-#include <win32.h>
+
+#ifdef _MSC_VER
+#include <winsock2.h> /* For struct timeval */
+#endif
int main(int argc, char **argv) {
unsigned int j, isunix = 0;
diff --git a/deps/hiredis/fmacros.h b/deps/hiredis/fmacros.h
index 3227faafd..754a53c21 100644
--- a/deps/hiredis/fmacros.h
+++ b/deps/hiredis/fmacros.h
@@ -1,8 +1,10 @@
#ifndef __HIREDIS_FMACRO_H
#define __HIREDIS_FMACRO_H
+#ifndef _AIX
#define _XOPEN_SOURCE 600
#define _POSIX_C_SOURCE 200112L
+#endif
#if defined(__APPLE__) && defined(__MACH__)
/* Enable TCP_KEEPALIVE */
diff --git a/deps/hiredis/fuzzing/format_command_fuzzer.c b/deps/hiredis/fuzzing/format_command_fuzzer.c
new file mode 100644
index 000000000..91adeac58
--- /dev/null
+++ b/deps/hiredis/fuzzing/format_command_fuzzer.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2020, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ * Copyright (c) 2020, 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 <stdlib.h>
+#include <string.h>
+#include "hiredis.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ char *new_str, *cmd;
+
+ if (size < 3)
+ return 0;
+
+ new_str = malloc(size+1);
+ if (new_str == NULL)
+ return 0;
+
+ memcpy(new_str, data, size);
+ new_str[size] = '\0';
+
+ redisFormatCommand(&cmd, new_str);
+
+ if (cmd != NULL)
+ hi_free(cmd);
+ free(new_str);
+ return 0;
+}
diff --git a/deps/hiredis/hiredis.c b/deps/hiredis/hiredis.c
index 51f22a665..91086f6f6 100644
--- a/deps/hiredis/hiredis.c
+++ b/deps/hiredis/hiredis.c
@@ -96,6 +96,8 @@ void freeReplyObject(void *reply) {
switch(r->type) {
case REDIS_REPLY_INTEGER:
+ case REDIS_REPLY_NIL:
+ case REDIS_REPLY_BOOL:
break; /* Nothing to free */
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
@@ -112,6 +114,7 @@ void freeReplyObject(void *reply) {
case REDIS_REPLY_STRING:
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_VERB:
+ case REDIS_REPLY_BIGNUM:
hi_free(r->str);
break;
}
@@ -129,7 +132,8 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
assert(task->type == REDIS_REPLY_ERROR ||
task->type == REDIS_REPLY_STATUS ||
task->type == REDIS_REPLY_STRING ||
- task->type == REDIS_REPLY_VERB);
+ task->type == REDIS_REPLY_VERB ||
+ task->type == REDIS_REPLY_BIGNUM);
/* Copy string value */
if (task->type == REDIS_REPLY_VERB) {
@@ -235,12 +239,14 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s
* decimal string conversion artifacts. */
memcpy(r->str, str, len);
r->str[len] = '\0';
+ r->len = len;
if (task->parent) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
- parent->type == REDIS_REPLY_SET);
+ parent->type == REDIS_REPLY_SET ||
+ parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
}
return r;
@@ -277,7 +283,8 @@ static void *createBoolObject(const redisReadTask *task, int bval) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
- parent->type == REDIS_REPLY_SET);
+ parent->type == REDIS_REPLY_SET ||
+ parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
}
return r;
@@ -306,7 +313,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
const char *c = format;
char *cmd = NULL; /* final command */
int pos; /* position in final command */
- hisds curarg, newarg; /* current argument */
+ sds curarg, newarg; /* current argument */
int touched = 0; /* was the current argument touched? */
char **curargv = NULL, **newargv = NULL;
int argc = 0;
@@ -319,7 +326,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
return -1;
/* Build the command string accordingly to protocol */
- curarg = hi_sdsempty();
+ curarg = sdsempty();
if (curarg == NULL)
return -1;
@@ -331,15 +338,15 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if (newargv == NULL) goto memory_err;
curargv = newargv;
curargv[argc++] = curarg;
- totlen += bulklen(hi_sdslen(curarg));
+ totlen += bulklen(sdslen(curarg));
/* curarg is put in argv so it can be overwritten. */
- curarg = hi_sdsempty();
+ curarg = sdsempty();
if (curarg == NULL) goto memory_err;
touched = 0;
}
} else {
- newarg = hi_sdscatlen(curarg,c,1);
+ newarg = sdscatlen(curarg,c,1);
if (newarg == NULL) goto memory_err;
curarg = newarg;
touched = 1;
@@ -356,16 +363,16 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
arg = va_arg(ap,char*);
size = strlen(arg);
if (size > 0)
- newarg = hi_sdscatlen(curarg,arg,size);
+ newarg = sdscatlen(curarg,arg,size);
break;
case 'b':
arg = va_arg(ap,char*);
size = va_arg(ap,size_t);
if (size > 0)
- newarg = hi_sdscatlen(curarg,arg,size);
+ newarg = sdscatlen(curarg,arg,size);
break;
case '%':
- newarg = hi_sdscat(curarg,"%");
+ newarg = sdscat(curarg,"%");
break;
default:
/* Try to detect printf format */
@@ -453,7 +460,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if (_l < sizeof(_format)-2) {
memcpy(_format,c,_l);
_format[_l] = '\0';
- newarg = hi_sdscatvprintf(curarg,_format,_cpy);
+ newarg = sdscatvprintf(curarg,_format,_cpy);
/* Update current position (note: outer blocks
* increment c twice so compensate here) */
@@ -480,9 +487,9 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if (newargv == NULL) goto memory_err;
curargv = newargv;
curargv[argc++] = curarg;
- totlen += bulklen(hi_sdslen(curarg));
+ totlen += bulklen(sdslen(curarg));
} else {
- hi_sdsfree(curarg);
+ sdsfree(curarg);
}
/* Clear curarg because it was put in curargv or was free'd. */
@@ -497,10 +504,10 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
pos = sprintf(cmd,"*%d\r\n",argc);
for (j = 0; j < argc; j++) {
- pos += sprintf(cmd+pos,"$%zu\r\n",hi_sdslen(curargv[j]));
- memcpy(cmd+pos,curargv[j],hi_sdslen(curargv[j]));
- pos += hi_sdslen(curargv[j]);
- hi_sdsfree(curargv[j]);
+ pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
+ memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
+ pos += sdslen(curargv[j]);
+ sdsfree(curargv[j]);
cmd[pos++] = '\r';
cmd[pos++] = '\n';
}
@@ -522,11 +529,11 @@ memory_err:
cleanup:
if (curargv) {
while(argc--)
- hi_sdsfree(curargv[argc]);
+ sdsfree(curargv[argc]);
hi_free(curargv);
}
- hi_sdsfree(curarg);
+ sdsfree(curarg);
hi_free(cmd);
return error_type;
@@ -559,19 +566,18 @@ int redisFormatCommand(char **target, const char *format, ...) {
return len;
}
-/* Format a command according to the Redis protocol using an hisds string and
- * hi_sdscatfmt for the processing of arguments. This function takes the
+/* Format a command according to the Redis protocol using an sds string and
+ * sdscatfmt for the processing of arguments. This function takes the
* number of arguments, an array with arguments and an array with their
* lengths. If the latter is set to NULL, strlen will be used to compute the
* argument lengths.
*/
-int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
- const size_t *argvlen)
+long long redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
+ const size_t *argvlen)
{
- hisds cmd, aux;
- unsigned long long totlen;
+ sds cmd, aux;
+ unsigned long long totlen, len;
int j;
- size_t len;
/* Abort on a NULL target */
if (target == NULL)
@@ -585,36 +591,36 @@ int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
}
/* Use an SDS string for command construction */
- cmd = hi_sdsempty();
+ cmd = sdsempty();
if (cmd == NULL)
return -1;
/* We already know how much storage we need */
- aux = hi_sdsMakeRoomFor(cmd, totlen);
+ aux = sdsMakeRoomFor(cmd, totlen);
if (aux == NULL) {
- hi_sdsfree(cmd);
+ sdsfree(cmd);
return -1;
}
cmd = aux;
/* Construct command */
- cmd = hi_sdscatfmt(cmd, "*%i\r\n", argc);
+ cmd = sdscatfmt(cmd, "*%i\r\n", argc);
for (j=0; j < argc; j++) {
len = argvlen ? argvlen[j] : strlen(argv[j]);
- cmd = hi_sdscatfmt(cmd, "$%u\r\n", len);
- cmd = hi_sdscatlen(cmd, argv[j], len);
- cmd = hi_sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
+ cmd = sdscatfmt(cmd, "$%U\r\n", len);
+ cmd = sdscatlen(cmd, argv[j], len);
+ cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
}
- assert(hi_sdslen(cmd)==totlen);
+ assert(sdslen(cmd)==totlen);
*target = cmd;
return totlen;
}
-void redisFreeSdsCommand(hisds cmd) {
- hi_sdsfree(cmd);
+void redisFreeSdsCommand(sds cmd) {
+ sdsfree(cmd);
}
/* Format a command according to the Redis protocol. This function takes the
@@ -622,11 +628,11 @@ void redisFreeSdsCommand(hisds cmd) {
* lengths. If the latter is set to NULL, strlen will be used to compute the
* argument lengths.
*/
-int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
+long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
char *cmd = NULL; /* final command */
- int pos; /* position in final command */
- size_t len;
- int totlen, j;
+ size_t pos; /* position in final command */
+ size_t len, totlen;
+ int j;
/* Abort on a NULL target */
if (target == NULL)
@@ -698,7 +704,7 @@ static redisContext *redisContextInit(void) {
c->funcs = &redisContextDefaultFuncs;
- c->obuf = hi_sdsempty();
+ c->obuf = sdsempty();
c->reader = redisReaderCreate();
c->fd = REDIS_INVALID_FD;
@@ -715,7 +721,7 @@ void redisFree(redisContext *c) {
return;
redisNetClose(c);
- hi_sdsfree(c->obuf);
+ sdsfree(c->obuf);
redisReaderFree(c->reader);
hi_free(c->tcp.host);
hi_free(c->tcp.source_addr);
@@ -752,10 +758,10 @@ int redisReconnect(redisContext *c) {
redisNetClose(c);
- hi_sdsfree(c->obuf);
+ sdsfree(c->obuf);
redisReaderFree(c->reader);
- c->obuf = hi_sdsempty();
+ c->obuf = sdsempty();
c->reader = redisReaderCreate();
if (c->obuf == NULL || c->reader == NULL) {
@@ -797,6 +803,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
if (options->options & REDIS_OPT_NOAUTOFREE) {
c->flags |= REDIS_NO_AUTO_FREE;
}
+ if (options->options & REDIS_OPT_NOAUTOFREEREPLIES) {
+ c->flags |= REDIS_NO_AUTO_FREE_REPLIES;
+ }
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
* as a default unless specifically flagged that we don't want one. */
@@ -825,7 +834,7 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
c->fd = options->endpoint.fd;
c->flags |= REDIS_CONNECTED;
} else {
- // Unknown type - FIXME - FREE
+ redisFree(c);
return NULL;
}
@@ -939,13 +948,11 @@ int redisBufferRead(redisContext *c) {
return REDIS_ERR;
nread = c->funcs->read(c, buf, sizeof(buf));
- if (nread > 0) {
- if (redisReaderFeed(c->reader, buf, nread) != REDIS_OK) {
- __redisSetError(c, c->reader->err, c->reader->errstr);
- return REDIS_ERR;
- } else {
- }
- } else if (nread < 0) {
+ if (nread < 0) {
+ return REDIS_ERR;
+ }
+ if (nread > 0 && redisReaderFeed(c->reader, buf, nread) != REDIS_OK) {
+ __redisSetError(c, c->reader->err, c->reader->errstr);
return REDIS_ERR;
}
return REDIS_OK;
@@ -966,22 +973,22 @@ int redisBufferWrite(redisContext *c, int *done) {
if (c->err)
return REDIS_ERR;
- if (hi_sdslen(c->obuf) > 0) {
+ if (sdslen(c->obuf) > 0) {
ssize_t nwritten = c->funcs->write(c);
if (nwritten < 0) {
return REDIS_ERR;
} else if (nwritten > 0) {
- if (nwritten == (ssize_t)hi_sdslen(c->obuf)) {
- hi_sdsfree(c->obuf);
- c->obuf = hi_sdsempty();
+ if (nwritten == (ssize_t)sdslen(c->obuf)) {
+ sdsfree(c->obuf);
+ c->obuf = sdsempty();
if (c->obuf == NULL)
goto oom;
} else {
- if (hi_sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
+ if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom;
}
}
}
- if (done != NULL) *done = (hi_sdslen(c->obuf) == 0);
+ if (done != NULL) *done = (sdslen(c->obuf) == 0);
return REDIS_OK;
oom:
@@ -989,17 +996,6 @@ oom:
return REDIS_ERR;
}
-/* Internal helper function to try and get a reply from the reader,
- * or set an error in the context otherwise. */
-int redisGetReplyFromReader(redisContext *c, void **reply) {
- if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
- __redisSetError(c,c->reader->err,c->reader->errstr);
- return REDIS_ERR;
- }
-
- return REDIS_OK;
-}
-
/* Internal helper that returns 1 if the reply was a RESP3 PUSH
* message and we handled it with a user-provided callback. */
static int redisHandledPushReply(redisContext *c, void *reply) {
@@ -1011,12 +1007,34 @@ static int redisHandledPushReply(redisContext *c, void *reply) {
return 0;
}
+/* Get a reply from our reader or set an error in the context. */
+int redisGetReplyFromReader(redisContext *c, void **reply) {
+ if (redisReaderGetReply(c->reader, reply) == REDIS_ERR) {
+ __redisSetError(c,c->reader->err,c->reader->errstr);
+ return REDIS_ERR;
+ }
+
+ return REDIS_OK;
+}
+
+/* Internal helper to get the next reply from our reader while handling
+ * any PUSH messages we encounter along the way. This is separate from
+ * redisGetReplyFromReader so as to not change its behavior. */
+static int redisNextInBandReplyFromReader(redisContext *c, void **reply) {
+ do {
+ if (redisGetReplyFromReader(c, reply) == REDIS_ERR)
+ return REDIS_ERR;
+ } while (redisHandledPushReply(c, *reply));
+
+ return REDIS_OK;
+}
+
int redisGetReply(redisContext *c, void **reply) {
int wdone = 0;
void *aux = NULL;
/* Try to read pending replies */
- if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
+ if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR)
return REDIS_ERR;
/* For the blocking context, flush output buffer and read reply */
@@ -1032,12 +1050,8 @@ int redisGetReply(redisContext *c, void **reply) {
if (redisBufferRead(c) == REDIS_ERR)
return REDIS_ERR;
- /* We loop here in case the user has specified a RESP3
- * PUSH handler (e.g. for client tracking). */
- do {
- if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)
- return REDIS_ERR;
- } while (redisHandledPushReply(c, aux));
+ if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR)
+ return REDIS_ERR;
} while (aux == NULL);
}
@@ -1059,9 +1073,9 @@ int redisGetReply(redisContext *c, void **reply) {
* the reply (or replies in pub/sub).
*/
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
- hisds newbuf;
+ sds newbuf;
- newbuf = hi_sdscatlen(c->obuf,cmd,len);
+ newbuf = sdscatlen(c->obuf,cmd,len);
if (newbuf == NULL) {
__redisSetError(c,REDIS_ERR_OOM,"Out of memory");
return REDIS_ERR;
@@ -1113,8 +1127,8 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
}
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
- hisds cmd;
- int len;
+ sds cmd;
+ long long len;
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
if (len == -1) {
@@ -1123,11 +1137,11 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
}
if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
- hi_sdsfree(cmd);
+ sdsfree(cmd);
return REDIS_ERR;
}
- hi_sdsfree(cmd);
+ sdsfree(cmd);
return REDIS_OK;
}
diff --git a/deps/hiredis/hiredis.h b/deps/hiredis/hiredis.h
index b597394d4..b378128b5 100644
--- a/deps/hiredis/hiredis.h
+++ b/deps/hiredis/hiredis.h
@@ -42,13 +42,13 @@ struct timeval; /* forward declaration */
typedef long long ssize_t;
#endif
#include <stdint.h> /* uintXX_t, etc */
-#include "sds.h" /* for hisds */
+#include "sds.h" /* for sds */
#include "alloc.h" /* for allocation wrappers */
#define HIREDIS_MAJOR 1
#define HIREDIS_MINOR 0
-#define HIREDIS_PATCH 0
-#define HIREDIS_SONAME 1.0.0
+#define HIREDIS_PATCH 3
+#define HIREDIS_SONAME 1.0.3-dev
/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
@@ -80,12 +80,18 @@ typedef long long ssize_t;
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
#define REDIS_REUSEADDR 0x80
+/* Flag that is set when the async connection supports push replies. */
+#define REDIS_SUPPORTS_PUSH 0x100
+
/**
* Flag that indicates the user does not want the context to
* be automatically freed upon error
*/
#define REDIS_NO_AUTO_FREE 0x200
+/* Flag that indicates the user does not want replies to be automatically freed */
+#define REDIS_NO_AUTO_FREE_REPLIES 0x400
+
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
@@ -112,7 +118,8 @@ typedef struct redisReply {
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). */
+ REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval),
+ and REDIS_REPLY_BIGNUM. */
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 */
@@ -127,10 +134,10 @@ 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(hisds *target, int argc, const char ** argv, const size_t *argvlen);
+long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
+long long redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
void redisFreeCommand(char *cmd);
-void redisFreeSdsCommand(hisds cmd);
+void redisFreeSdsCommand(sds cmd);
enum redisConnectionType {
REDIS_CONN_TCP,
@@ -152,6 +159,11 @@ struct redisSsl;
/* Don't automatically intercept and free RESP3 PUSH replies. */
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
+/**
+ * Don't automatically free replies
+ */
+#define REDIS_OPT_NOAUTOFREEREPLIES 0x10
+
/* 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
@@ -255,7 +267,7 @@ typedef struct redisContext {
} unix_sock;
/* For non-blocking connect */
- struct sockadr *saddr;
+ struct sockaddr *saddr;
size_t addrlen;
/* Optional data and corresponding destructor users can use to provide
diff --git a/deps/hiredis/hiredis.targets b/deps/hiredis/hiredis.targets
new file mode 100644
index 000000000..effd8a561
--- /dev/null
+++ b/deps/hiredis/hiredis.targets
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>$(MSBuildThisFileDirectory)\..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+</Project> \ No newline at end of file
diff --git a/deps/hiredis/hiredis_ssl.h b/deps/hiredis/hiredis_ssl.h
index 604efe0c1..e3d3e1cf5 100644
--- a/deps/hiredis/hiredis_ssl.h
+++ b/deps/hiredis/hiredis_ssl.h
@@ -56,7 +56,9 @@ typedef enum {
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 */
+ REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED, /* Failed to load private key */
+ REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED, /* Failed to open system certifcate store */
+ REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */
} redisSSLContextError;
/**
diff --git a/deps/hiredis/net.c b/deps/hiredis/net.c
index 88f9aff25..c6b0e5d8e 100644
--- a/deps/hiredis/net.c
+++ b/deps/hiredis/net.c
@@ -80,7 +80,7 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
}
ssize_t redisNetWrite(redisContext *c) {
- ssize_t nwritten = send(c->fd, c->obuf, hi_sdslen(c->obuf), 0);
+ 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 */
diff --git a/deps/hiredis/read.c b/deps/hiredis/read.c
index 682b9a6b9..de62b9ab0 100644
--- a/deps/hiredis/read.c
+++ b/deps/hiredis/read.c
@@ -59,7 +59,7 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
}
/* Clear input buffer on errors. */
- hi_sdsfree(r->buf);
+ sdsfree(r->buf);
r->buf = NULL;
r->pos = r->len = 0;
@@ -123,29 +123,28 @@ static char *readBytes(redisReader *r, unsigned int bytes) {
/* 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++;
- }
+ char *ret;
+
+ /* We cannot match with fewer than 2 bytes */
+ if (len < 2)
+ return NULL;
+
+ /* Search up to len - 1 characters */
+ len--;
+
+ /* Look for the \r */
+ while ((ret = memchr(s, '\r', len)) != NULL) {
+ if (ret[1] == '\n') {
+ /* Found. */
+ break;
}
+ /* Continue searching. */
+ ret++;
+ len -= ret - s;
+ s = ret;
}
- return NULL;
+
+ return ret;
}
/* Convert a string into a long long. Returns REDIS_OK if the string could be
@@ -274,60 +273,104 @@ static int processLineItem(redisReader *r) {
if ((p = readLine(r,&len)) != NULL) {
if (cur->type == REDIS_REPLY_INTEGER) {
+ long long v;
+
+ if (string2ll(p, len, &v) == REDIS_ERR) {
+ __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
+ "Bad integer value");
+ return REDIS_ERR;
+ }
+
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;
+ char buf[326], *eptr;
+ double d;
- if ((size_t)len >= sizeof(buf)) {
+ 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 (len == 3 && strcasecmp(buf,"inf") == 0) {
+ d = INFINITY; /* Positive infinite. */
+ } else if (len == 4 && strcasecmp(buf,"-inf") == 0) {
+ d = -INFINITY; /* Negative infinite. */
+ } else {
+ d = strtod((char*)buf,&eptr);
+ /* RESP3 only allows "inf", "-inf", and finite values, while
+ * strtod() allows other variations on infinity, NaN,
+ * etc. We explicity handle our two allowed infinite cases
+ * above, so strtod() should only result in finite values. */
+ if (buf[0] == '\0' || eptr != &buf[len] || !isfinite(d)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
- "Double value is too large");
+ "Bad double value");
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;
- }
- }
+ if (r->fn && r->fn->createDouble) {
obj = r->fn->createDouble(cur,d,buf,len);
} else {
obj = (void*)REDIS_REPLY_DOUBLE;
}
} else if (cur->type == REDIS_REPLY_NIL) {
+ if (len != 0) {
+ __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
+ "Bad nil value");
+ return REDIS_ERR;
+ }
+
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';
+ int bval;
+
+ if (len != 1 || !strchr("tTfF", p[0])) {
+ __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
+ "Bad bool value");
+ return REDIS_ERR;
+ }
+
+ 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 if (cur->type == REDIS_REPLY_BIGNUM) {
+ /* Ensure all characters are decimal digits (with possible leading
+ * minus sign). */
+ for (int i = 0; i < len; i++) {
+ /* XXX Consider: Allow leading '+'? Error on leading '0's? */
+ if (i == 0 && p[0] == '-') continue;
+ if (p[i] < '0' || p[i] > '9') {
+ __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
+ "Bad bignum value");
+ return REDIS_ERR;
+ }
+ }
+ if (r->fn && r->fn->createString)
+ obj = r->fn->createString(cur,p,len);
+ else
+ obj = (void*)REDIS_REPLY_BIGNUM;
} else {
/* Type will be error or status. */
+ for (int i = 0; i < len; i++) {
+ if (p[i] == '\r' || p[i] == '\n') {
+ __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
+ "Bad simple string value");
+ return REDIS_ERR;
+ }
+ }
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,p,len);
else
@@ -453,7 +496,6 @@ static int processAggregateItem(redisReader *r) {
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;
@@ -569,6 +611,9 @@ static int processItem(redisReader *r) {
case '>':
cur->type = REDIS_REPLY_PUSH;
break;
+ case '(':
+ cur->type = REDIS_REPLY_BIGNUM;
+ break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
@@ -587,6 +632,7 @@ static int processItem(redisReader *r) {
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_NIL:
case REDIS_REPLY_BOOL:
+ case REDIS_REPLY_BIGNUM:
return processLineItem(r);
case REDIS_REPLY_STRING:
case REDIS_REPLY_VERB:
@@ -609,7 +655,7 @@ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
if (r == NULL)
return NULL;
- r->buf = hi_sdsempty();
+ r->buf = sdsempty();
if (r->buf == NULL)
goto oom;
@@ -650,12 +696,12 @@ void redisReaderFree(redisReader *r) {
hi_free(r->task);
}
- hi_sdsfree(r->buf);
+ sdsfree(r->buf);
hi_free(r);
}
int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
- hisds newbuf;
+ sds newbuf;
/* Return early when this reader is in an erroneous state. */
if (r->err)
@@ -664,19 +710,19 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
/* 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 && hi_sdsavail(r->buf) > r->maxbuf) {
- hi_sdsfree(r->buf);
- r->buf = hi_sdsempty();
+ 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 = hi_sdscatlen(r->buf,buf,len);
+ newbuf = sdscatlen(r->buf,buf,len);
if (newbuf == NULL) goto oom;
r->buf = newbuf;
- r->len = hi_sdslen(r->buf);
+ r->len = sdslen(r->buf);
}
return REDIS_OK;
@@ -721,9 +767,9 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* 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 (hi_sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
+ if (sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR;
r->pos = 0;
- r->len = hi_sdslen(r->buf);
+ r->len = sdslen(r->buf);
}
/* Emit a reply when there is one. */
diff --git a/deps/hiredis/sds.c b/deps/hiredis/sds.c
index 675e7649f..35baa057e 100644
--- a/deps/hiredis/sds.c
+++ b/deps/hiredis/sds.c
@@ -40,90 +40,90 @@
#include "sds.h"
#include "sdsalloc.h"
-static inline int hi_sdsHdrSize(char type) {
- switch(type&HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5:
- return sizeof(struct hisdshdr5);
- case HI_SDS_TYPE_8:
- return sizeof(struct hisdshdr8);
- case HI_SDS_TYPE_16:
- return sizeof(struct hisdshdr16);
- case HI_SDS_TYPE_32:
- return sizeof(struct hisdshdr32);
- case HI_SDS_TYPE_64:
- return sizeof(struct hisdshdr64);
+static inline int sdsHdrSize(char type) {
+ switch(type&SDS_TYPE_MASK) {
+ case SDS_TYPE_5:
+ return sizeof(struct sdshdr5);
+ case SDS_TYPE_8:
+ return sizeof(struct sdshdr8);
+ case SDS_TYPE_16:
+ return sizeof(struct sdshdr16);
+ case SDS_TYPE_32:
+ return sizeof(struct sdshdr32);
+ case SDS_TYPE_64:
+ return sizeof(struct sdshdr64);
}
return 0;
}
-static inline char hi_sdsReqType(size_t string_size) {
+static inline char sdsReqType(size_t string_size) {
if (string_size < 32)
- return HI_SDS_TYPE_5;
+ return SDS_TYPE_5;
if (string_size < 0xff)
- return HI_SDS_TYPE_8;
+ return SDS_TYPE_8;
if (string_size < 0xffff)
- return HI_SDS_TYPE_16;
+ return SDS_TYPE_16;
if (string_size < 0xffffffff)
- return HI_SDS_TYPE_32;
- return HI_SDS_TYPE_64;
+ return SDS_TYPE_32;
+ return SDS_TYPE_64;
}
-/* Create a new hisds string with the content specified by the 'init' pointer
+/* Create a new sds string with the content specified by the 'init' pointer
* and 'initlen'.
* If NULL is used for 'init' the string is initialized with zero bytes.
*
- * The string is always null-termined (all the hisds strings are, always) so
- * even if you create an hisds string with:
+ * The string is always null-terminated (all the sds strings are, always) so
+ * even if you create an sds string with:
*
- * mystring = hi_sdsnewlen("abc",3);
+ * mystring = sdsnewlen("abc",3);
*
* You can print the string with printf() as there is an implicit \0 at the
* end of the string. However the string is binary safe and can contain
- * \0 characters in the middle, as the length is stored in the hisds header. */
-hisds hi_sdsnewlen(const void *init, size_t initlen) {
+ * \0 characters in the middle, as the length is stored in the sds header. */
+sds sdsnewlen(const void *init, size_t initlen) {
void *sh;
- hisds s;
- char type = hi_sdsReqType(initlen);
+ sds s;
+ char type = sdsReqType(initlen);
/* Empty strings are usually created in order to append. Use type 8
* since type 5 is not good at this. */
- if (type == HI_SDS_TYPE_5 && initlen == 0) type = HI_SDS_TYPE_8;
- int hdrlen = hi_sdsHdrSize(type);
+ if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
+ int hdrlen = sdsHdrSize(type);
unsigned char *fp; /* flags pointer. */
- sh = hi_s_malloc(hdrlen+initlen+1);
+ sh = s_malloc(hdrlen+initlen+1);
if (sh == NULL) return NULL;
if (!init)
memset(sh, 0, hdrlen+initlen+1);
s = (char*)sh+hdrlen;
fp = ((unsigned char*)s)-1;
switch(type) {
- case HI_SDS_TYPE_5: {
- *fp = type | (initlen << HI_SDS_TYPE_BITS);
+ case SDS_TYPE_5: {
+ *fp = type | (initlen << SDS_TYPE_BITS);
break;
}
- case HI_SDS_TYPE_8: {
- HI_SDS_HDR_VAR(8,s);
+ case SDS_TYPE_8: {
+ SDS_HDR_VAR(8,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break;
}
- case HI_SDS_TYPE_16: {
- HI_SDS_HDR_VAR(16,s);
+ case SDS_TYPE_16: {
+ SDS_HDR_VAR(16,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break;
}
- case HI_SDS_TYPE_32: {
- HI_SDS_HDR_VAR(32,s);
+ case SDS_TYPE_32: {
+ SDS_HDR_VAR(32,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break;
}
- case HI_SDS_TYPE_64: {
- HI_SDS_HDR_VAR(64,s);
+ case SDS_TYPE_64: {
+ SDS_HDR_VAR(64,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
@@ -136,164 +136,164 @@ hisds hi_sdsnewlen(const void *init, size_t initlen) {
return s;
}
-/* Create an empty (zero length) hisds string. Even in this case the string
+/* Create an empty (zero length) sds string. Even in this case the string
* always has an implicit null term. */
-hisds hi_sdsempty(void) {
- return hi_sdsnewlen("",0);
+sds sdsempty(void) {
+ return sdsnewlen("",0);
}
-/* Create a new hisds string starting from a null terminated C string. */
-hisds hi_sdsnew(const char *init) {
+/* Create a new sds string starting from a null terminated C string. */
+sds sdsnew(const char *init) {
size_t initlen = (init == NULL) ? 0 : strlen(init);
- return hi_sdsnewlen(init, initlen);
+ return sdsnewlen(init, initlen);
}
-/* Duplicate an hisds string. */
-hisds hi_sdsdup(const hisds s) {
- return hi_sdsnewlen(s, hi_sdslen(s));
+/* Duplicate an sds string. */
+sds sdsdup(const sds s) {
+ return sdsnewlen(s, sdslen(s));
}
-/* Free an hisds string. No operation is performed if 's' is NULL. */
-void hi_sdsfree(hisds s) {
+/* Free an sds string. No operation is performed if 's' is NULL. */
+void sdsfree(sds s) {
if (s == NULL) return;
- hi_s_free((char*)s-hi_sdsHdrSize(s[-1]));
+ s_free((char*)s-sdsHdrSize(s[-1]));
}
-/* Set the hisds string length to the length as obtained with strlen(), so
+/* Set the sds string length to the length as obtained with strlen(), so
* considering as content only up to the first null term character.
*
- * This function is useful when the hisds string is hacked manually in some
+ * This function is useful when the sds string is hacked manually in some
* way, like in the following example:
*
- * s = hi_sdsnew("foobar");
+ * s = sdsnew("foobar");
* s[2] = '\0';
- * hi_sdsupdatelen(s);
- * printf("%d\n", hi_sdslen(s));
+ * sdsupdatelen(s);
+ * printf("%d\n", sdslen(s));
*
- * The output will be "2", but if we comment out the call to hi_sdsupdatelen()
+ * The output will be "2", but if we comment out the call to sdsupdatelen()
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
-void hi_sdsupdatelen(hisds s) {
+void sdsupdatelen(sds s) {
int reallen = strlen(s);
- hi_sdssetlen(s, reallen);
+ sdssetlen(s, reallen);
}
-/* Modify an hisds string in-place to make it empty (zero length).
+/* Modify an sds string in-place to make it empty (zero length).
* However all the existing buffer is not discarded but set as free space
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
-void hi_sdsclear(hisds s) {
- hi_sdssetlen(s, 0);
+void sdsclear(sds s) {
+ sdssetlen(s, 0);
s[0] = '\0';
}
-/* Enlarge the free space at the end of the hisds string so that the caller
+/* Enlarge the free space at the end of the sds string so that the caller
* is sure that after calling this function can overwrite up to addlen
* bytes after the end of the string, plus one more byte for nul term.
*
- * Note: this does not change the *length* of the hisds string as returned
- * by hi_sdslen(), but only the free buffer space we have. */
-hisds hi_sdsMakeRoomFor(hisds s, size_t addlen) {
+ * Note: this does not change the *length* of the sds string as returned
+ * by sdslen(), but only the free buffer space we have. */
+sds sdsMakeRoomFor(sds s, size_t addlen) {
void *sh, *newsh;
- size_t avail = hi_sdsavail(s);
+ size_t avail = sdsavail(s);
size_t len, newlen;
- char type, oldtype = s[-1] & HI_SDS_TYPE_MASK;
+ char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen;
/* Return ASAP if there is enough space left. */
if (avail >= addlen) return s;
- len = hi_sdslen(s);
- sh = (char*)s-hi_sdsHdrSize(oldtype);
+ len = sdslen(s);
+ sh = (char*)s-sdsHdrSize(oldtype);
newlen = (len+addlen);
- if (newlen < HI_SDS_MAX_PREALLOC)
+ if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
else
- newlen += HI_SDS_MAX_PREALLOC;
+ newlen += SDS_MAX_PREALLOC;
- type = hi_sdsReqType(newlen);
+ type = sdsReqType(newlen);
/* Don't use type 5: the user is appending to the string and type 5 is
- * not able to remember empty space, so hi_sdsMakeRoomFor() must be called
+ * not able to remember empty space, so sdsMakeRoomFor() must be called
* at every appending operation. */
- if (type == HI_SDS_TYPE_5) type = HI_SDS_TYPE_8;
+ if (type == SDS_TYPE_5) type = SDS_TYPE_8;
- hdrlen = hi_sdsHdrSize(type);
+ hdrlen = sdsHdrSize(type);
if (oldtype==type) {
- newsh = hi_s_realloc(sh, hdrlen+newlen+1);
+ newsh = s_realloc(sh, hdrlen+newlen+1);
if (newsh == NULL) return NULL;
s = (char*)newsh+hdrlen;
} else {
/* Since the header size changes, need to move the string forward,
* and can't use realloc */
- newsh = hi_s_malloc(hdrlen+newlen+1);
+ newsh = s_malloc(hdrlen+newlen+1);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len+1);
- hi_s_free(sh);
+ s_free(sh);
s = (char*)newsh+hdrlen;
s[-1] = type;
- hi_sdssetlen(s, len);
+ sdssetlen(s, len);
}
- hi_sdssetalloc(s, newlen);
+ sdssetalloc(s, newlen);
return s;
}
-/* Reallocate the hisds string so that it has no free space at the end. The
+/* Reallocate the sds string so that it has no free space at the end. The
* contained string remains not altered, but next concatenation operations
* will require a reallocation.
*
- * After the call, the passed hisds string is no longer valid and all the
+ * After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
-hisds hi_sdsRemoveFreeSpace(hisds s) {
+sds sdsRemoveFreeSpace(sds s) {
void *sh, *newsh;
- char type, oldtype = s[-1] & HI_SDS_TYPE_MASK;
+ char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen;
- size_t len = hi_sdslen(s);
- sh = (char*)s-hi_sdsHdrSize(oldtype);
+ size_t len = sdslen(s);
+ sh = (char*)s-sdsHdrSize(oldtype);
- type = hi_sdsReqType(len);
- hdrlen = hi_sdsHdrSize(type);
+ type = sdsReqType(len);
+ hdrlen = sdsHdrSize(type);
if (oldtype==type) {
- newsh = hi_s_realloc(sh, hdrlen+len+1);
+ newsh = s_realloc(sh, hdrlen+len+1);
if (newsh == NULL) return NULL;
s = (char*)newsh+hdrlen;
} else {
- newsh = hi_s_malloc(hdrlen+len+1);
+ newsh = s_malloc(hdrlen+len+1);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len+1);
- hi_s_free(sh);
+ s_free(sh);
s = (char*)newsh+hdrlen;
s[-1] = type;
- hi_sdssetlen(s, len);
+ sdssetlen(s, len);
}
- hi_sdssetalloc(s, len);
+ sdssetalloc(s, len);
return s;
}
-/* Return the total size of the allocation of the specifed hisds string,
+/* Return the total size of the allocation of the specifed sds string,
* including:
- * 1) The hisds header before the pointer.
+ * 1) The sds header before the pointer.
* 2) The string.
* 3) The free buffer at the end if any.
* 4) The implicit null term.
*/
-size_t hi_sdsAllocSize(hisds s) {
- size_t alloc = hi_sdsalloc(s);
- return hi_sdsHdrSize(s[-1])+alloc+1;
+size_t sdsAllocSize(sds s) {
+ size_t alloc = sdsalloc(s);
+ return sdsHdrSize(s[-1])+alloc+1;
}
/* Return the pointer of the actual SDS allocation (normally SDS strings
* are referenced by the start of the string buffer). */
-void *hi_sdsAllocPtr(hisds s) {
- return (void*) (s-hi_sdsHdrSize(s[-1]));
+void *sdsAllocPtr(sds s) {
+ return (void*) (s-sdsHdrSize(s[-1]));
}
-/* Increment the hisds length and decrements the left free space at the
+/* Increment the sds length and decrements the left free space at the
* end of the string according to 'incr'. Also set the null term
* in the new end of the string.
*
* This function is used in order to fix the string length after the
- * user calls hi_sdsMakeRoomFor(), writes something after the end of
+ * user calls sdsMakeRoomFor(), writes something after the end of
* the current string, and finally needs to set the new length.
*
* Note: it is possible to use a negative increment in order to
@@ -301,48 +301,48 @@ void *hi_sdsAllocPtr(hisds s) {
*
* Usage example:
*
- * Using hi_sdsIncrLen() and hi_sdsMakeRoomFor() it is possible to mount the
+ * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
* following schema, to cat bytes coming from the kernel to the end of an
- * hisds string without copying into an intermediate buffer:
+ * sds string without copying into an intermediate buffer:
*
- * oldlen = hi_hi_sdslen(s);
- * s = hi_sdsMakeRoomFor(s, BUFFER_SIZE);
+ * oldlen = sdslen(s);
+ * s = sdsMakeRoomFor(s, BUFFER_SIZE);
* nread = read(fd, s+oldlen, BUFFER_SIZE);
* ... check for nread <= 0 and handle it ...
- * hi_sdsIncrLen(s, nread);
+ * sdsIncrLen(s, nread);
*/
-void hi_sdsIncrLen(hisds s, int incr) {
+void sdsIncrLen(sds s, int incr) {
unsigned char flags = s[-1];
size_t len;
- switch(flags&HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5: {
+ switch(flags&SDS_TYPE_MASK) {
+ case SDS_TYPE_5: {
unsigned char *fp = ((unsigned char*)s)-1;
- unsigned char oldlen = HI_SDS_TYPE_5_LEN(flags);
+ unsigned char oldlen = SDS_TYPE_5_LEN(flags);
assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
- *fp = HI_SDS_TYPE_5 | ((oldlen+incr) << HI_SDS_TYPE_BITS);
+ *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
len = oldlen+incr;
break;
}
- case HI_SDS_TYPE_8: {
- HI_SDS_HDR_VAR(8,s);
+ case SDS_TYPE_8: {
+ SDS_HDR_VAR(8,s);
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
len = (sh->len += incr);
break;
}
- case HI_SDS_TYPE_16: {
- HI_SDS_HDR_VAR(16,s);
+ case SDS_TYPE_16: {
+ SDS_HDR_VAR(16,s);
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
len = (sh->len += incr);
break;
}
- case HI_SDS_TYPE_32: {
- HI_SDS_HDR_VAR(32,s);
+ case SDS_TYPE_32: {
+ SDS_HDR_VAR(32,s);
assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
len = (sh->len += incr);
break;
}
- case HI_SDS_TYPE_64: {
- HI_SDS_HDR_VAR(64,s);
+ case SDS_TYPE_64: {
+ SDS_HDR_VAR(64,s);
assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
len = (sh->len += incr);
break;
@@ -352,83 +352,83 @@ void hi_sdsIncrLen(hisds s, int incr) {
s[len] = '\0';
}
-/* Grow the hisds to have the specified length. Bytes that were not part of
- * the original length of the hisds will be set to zero.
+/* Grow the sds to have the specified length. Bytes that were not part of
+ * the original length of the sds will be set to zero.
*
* if the specified length is smaller than the current length, no operation
* is performed. */
-hisds hi_sdsgrowzero(hisds s, size_t len) {
- size_t curlen = hi_sdslen(s);
+sds sdsgrowzero(sds s, size_t len) {
+ size_t curlen = sdslen(s);
if (len <= curlen) return s;
- s = hi_sdsMakeRoomFor(s,len-curlen);
+ s = sdsMakeRoomFor(s,len-curlen);
if (s == NULL) return NULL;
/* Make sure added region doesn't contain garbage */
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
- hi_sdssetlen(s, len);
+ sdssetlen(s, len);
return s;
}
/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
- * end of the specified hisds string 's'.
+ * end of the specified sds string 's'.
*
- * After the call, the passed hisds string is no longer valid and all the
+ * After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
-hisds hi_sdscatlen(hisds s, const void *t, size_t len) {
- size_t curlen = hi_sdslen(s);
+sds sdscatlen(sds s, const void *t, size_t len) {
+ size_t curlen = sdslen(s);
- s = hi_sdsMakeRoomFor(s,len);
+ s = sdsMakeRoomFor(s,len);
if (s == NULL) return NULL;
memcpy(s+curlen, t, len);
- hi_sdssetlen(s, curlen+len);
+ sdssetlen(s, curlen+len);
s[curlen+len] = '\0';
return s;
}
-/* Append the specified null termianted C string to the hisds string 's'.
+/* Append the specified null termianted C string to the sds string 's'.
*
- * After the call, the passed hisds string is no longer valid and all the
+ * After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
-hisds hi_sdscat(hisds s, const char *t) {
- return hi_sdscatlen(s, t, strlen(t));
+sds sdscat(sds s, const char *t) {
+ return sdscatlen(s, t, strlen(t));
}
-/* Append the specified hisds 't' to the existing hisds 's'.
+/* Append the specified sds 't' to the existing sds 's'.
*
- * After the call, the modified hisds string is no longer valid and all the
+ * After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
-hisds hi_sdscatsds(hisds s, const hisds t) {
- return hi_sdscatlen(s, t, hi_sdslen(t));
+sds sdscatsds(sds s, const sds t) {
+ return sdscatlen(s, t, sdslen(t));
}
-/* Destructively modify the hisds string 's' to hold the specified binary
+/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
-hisds hi_sdscpylen(hisds s, const char *t, size_t len) {
- if (hi_sdsalloc(s) < len) {
- s = hi_sdsMakeRoomFor(s,len-hi_sdslen(s));
+sds sdscpylen(sds s, const char *t, size_t len) {
+ if (sdsalloc(s) < len) {
+ s = sdsMakeRoomFor(s,len-sdslen(s));
if (s == NULL) return NULL;
}
memcpy(s, t, len);
s[len] = '\0';
- hi_sdssetlen(s, len);
+ sdssetlen(s, len);
return s;
}
-/* Like hi_sdscpylen() but 't' must be a null-termined string so that the length
+/* Like sdscpylen() but 't' must be a null-terminated string so that the length
* of the string is obtained with strlen(). */
-hisds hi_sdscpy(hisds s, const char *t) {
- return hi_sdscpylen(s, t, strlen(t));
+sds sdscpy(sds s, const char *t) {
+ return sdscpylen(s, t, strlen(t));
}
-/* Helper for hi_sdscatlonglong() doing the actual number -> string
+/* Helper for sdscatlonglong() doing the actual number -> string
* conversion. 's' must point to a string with room for at least
- * HI_SDS_LLSTR_SIZE bytes.
+ * SDS_LLSTR_SIZE bytes.
*
* The function returns the length of the null-terminated string
* representation stored at 's'. */
-#define HI_SDS_LLSTR_SIZE 21
-int hi_sdsll2str(char *s, long long value) {
+#define SDS_LLSTR_SIZE 21
+int sdsll2str(char *s, long long value) {
char *p, aux;
unsigned long long v;
size_t l;
@@ -459,8 +459,8 @@ int hi_sdsll2str(char *s, long long value) {
return l;
}
-/* Identical hi_sdsll2str(), but for unsigned long long type. */
-int hi_sdsull2str(char *s, unsigned long long v) {
+/* Identical sdsll2str(), but for unsigned long long type. */
+int sdsull2str(char *s, unsigned long long v) {
char *p, aux;
size_t l;
@@ -488,19 +488,19 @@ int hi_sdsull2str(char *s, unsigned long long v) {
return l;
}
-/* Create an hisds string from a long long value. It is much faster than:
+/* Create an sds string from a long long value. It is much faster than:
*
- * hi_sdscatprintf(hi_sdsempty(),"%lld\n", value);
+ * sdscatprintf(sdsempty(),"%lld\n", value);
*/
-hisds hi_sdsfromlonglong(long long value) {
- char buf[HI_SDS_LLSTR_SIZE];
- int len = hi_sdsll2str(buf,value);
+sds sdsfromlonglong(long long value) {
+ char buf[SDS_LLSTR_SIZE];
+ int len = sdsll2str(buf,value);
- return hi_sdsnewlen(buf,len);
+ return sdsnewlen(buf,len);
}
-/* Like hi_sdscatprintf() but gets va_list instead of being variadic. */
-hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
+/* Like sdscatprintf() but gets va_list instead of being variadic. */
+sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
va_list cpy;
char staticbuf[1024], *buf = staticbuf, *t;
size_t buflen = strlen(fmt)*2;
@@ -508,7 +508,7 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
/* We try to start using a static buffer for speed.
* If not possible we revert to heap allocation. */
if (buflen > sizeof(staticbuf)) {
- buf = hi_s_malloc(buflen);
+ buf = s_malloc(buflen);
if (buf == NULL) return NULL;
} else {
buflen = sizeof(staticbuf);
@@ -522,9 +522,9 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
vsnprintf(buf, buflen, fmt, cpy);
va_end(cpy);
if (buf[buflen-2] != '\0') {
- if (buf != staticbuf) hi_s_free(buf);
+ if (buf != staticbuf) s_free(buf);
buflen *= 2;
- buf = hi_s_malloc(buflen);
+ buf = s_malloc(buflen);
if (buf == NULL) return NULL;
continue;
}
@@ -532,39 +532,39 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
}
/* Finally concat the obtained string to the SDS string and return it. */
- t = hi_sdscat(s, buf);
- if (buf != staticbuf) hi_s_free(buf);
+ t = sdscat(s, buf);
+ if (buf != staticbuf) s_free(buf);
return t;
}
-/* Append to the hisds string 's' a string obtained using printf-alike format
+/* Append to the sds string 's' a string obtained using printf-alike format
* specifier.
*
- * After the call, the modified hisds string is no longer valid and all the
+ * After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call.
*
* Example:
*
- * s = hi_sdsnew("Sum is: ");
- * s = hi_sdscatprintf(s,"%d+%d = %d",a,b,a+b).
+ * s = sdsnew("Sum is: ");
+ * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
*
* Often you need to create a string from scratch with the printf-alike
- * format. When this is the need, just use hi_sdsempty() as the target string:
+ * format. When this is the need, just use sdsempty() as the target string:
*
- * s = hi_sdscatprintf(hi_sdsempty(), "... your format ...", args);
+ * s = sdscatprintf(sdsempty(), "... your format ...", args);
*/
-hisds hi_sdscatprintf(hisds s, const char *fmt, ...) {
+sds sdscatprintf(sds s, const char *fmt, ...) {
va_list ap;
char *t;
va_start(ap, fmt);
- t = hi_sdscatvprintf(s,fmt,ap);
+ t = sdscatvprintf(s,fmt,ap);
va_end(ap);
return t;
}
-/* This function is similar to hi_sdscatprintf, but much faster as it does
+/* This function is similar to sdscatprintf, but much faster as it does
* not rely on sprintf() family functions implemented by the libc that
- * are often very slow. Moreover directly handling the hisds string as
+ * are often very slow. Moreover directly handling the sds string as
* new data is concatenated provides a performance improvement.
*
* However this function only handles an incompatible subset of printf-alike
@@ -578,13 +578,13 @@ hisds hi_sdscatprintf(hisds s, const char *fmt, ...) {
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %% - Verbatim "%" character.
*/
-hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
+sds sdscatfmt(sds s, char const *fmt, ...) {
const char *f = fmt;
int i;
va_list ap;
va_start(ap,fmt);
- i = hi_sdslen(s); /* Position of the next byte to write to dest str. */
+ i = sdslen(s); /* Position of the next byte to write to dest str. */
while(*f) {
char next, *str;
size_t l;
@@ -592,8 +592,8 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
unsigned long long unum;
/* Make sure there is always space for at least 1 char. */
- if (hi_sdsavail(s)==0) {
- s = hi_sdsMakeRoomFor(s,1);
+ if (sdsavail(s)==0) {
+ s = sdsMakeRoomFor(s,1);
if (s == NULL) goto fmt_error;
}
@@ -605,13 +605,13 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
case 's':
case 'S':
str = va_arg(ap,char*);
- l = (next == 's') ? strlen(str) : hi_sdslen(str);
- if (hi_sdsavail(s) < l) {
- s = hi_sdsMakeRoomFor(s,l);
+ l = (next == 's') ? strlen(str) : sdslen(str);
+ if (sdsavail(s) < l) {
+ s = sdsMakeRoomFor(s,l);
if (s == NULL) goto fmt_error;
}
memcpy(s+i,str,l);
- hi_sdsinclen(s,l);
+ sdsinclen(s,l);
i += l;
break;
case 'i':
@@ -621,14 +621,14 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
else
num = va_arg(ap,long long);
{
- char buf[HI_SDS_LLSTR_SIZE];
- l = hi_sdsll2str(buf,num);
- if (hi_sdsavail(s) < l) {
- s = hi_sdsMakeRoomFor(s,l);
+ char buf[SDS_LLSTR_SIZE];
+ l = sdsll2str(buf,num);
+ if (sdsavail(s) < l) {
+ s = sdsMakeRoomFor(s,l);
if (s == NULL) goto fmt_error;
}
memcpy(s+i,buf,l);
- hi_sdsinclen(s,l);
+ sdsinclen(s,l);
i += l;
}
break;
@@ -639,26 +639,26 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
else
unum = va_arg(ap,unsigned long long);
{
- char buf[HI_SDS_LLSTR_SIZE];
- l = hi_sdsull2str(buf,unum);
- if (hi_sdsavail(s) < l) {
- s = hi_sdsMakeRoomFor(s,l);
+ char buf[SDS_LLSTR_SIZE];
+ l = sdsull2str(buf,unum);
+ if (sdsavail(s) < l) {
+ s = sdsMakeRoomFor(s,l);
if (s == NULL) goto fmt_error;
}
memcpy(s+i,buf,l);
- hi_sdsinclen(s,l);
+ sdsinclen(s,l);
i += l;
}
break;
default: /* Handle %% and generally %<unknown>. */
s[i++] = next;
- hi_sdsinclen(s,1);
+ sdsinclen(s,1);
break;
}
break;
default:
s[i++] = *f;
- hi_sdsinclen(s,1);
+ sdsinclen(s,1);
break;
}
f++;
@@ -677,29 +677,29 @@ fmt_error:
/* Remove the part of the string from left and from right composed just of
* contiguous characters found in 'cset', that is a null terminted C string.
*
- * After the call, the modified hisds string is no longer valid and all the
+ * After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call.
*
* Example:
*
- * s = hi_sdsnew("AA...AA.a.aa.aHelloWorld :::");
- * s = hi_sdstrim(s,"Aa. :");
+ * s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
+ * s = sdstrim(s,"Aa. :");
* printf("%s\n", s);
*
* Output will be just "Hello World".
*/
-hisds hi_sdstrim(hisds s, const char *cset) {
+sds sdstrim(sds s, const char *cset) {
char *start, *end, *sp, *ep;
size_t len;
sp = start = s;
- ep = end = s+hi_sdslen(s)-1;
+ ep = end = s+sdslen(s)-1;
while(sp <= end && strchr(cset, *sp)) sp++;
while(ep > sp && strchr(cset, *ep)) ep--;
len = (sp > ep) ? 0 : ((ep-sp)+1);
if (s != sp) memmove(s, sp, len);
s[len] = '\0';
- hi_sdssetlen(s,len);
+ sdssetlen(s,len);
return s;
}
@@ -715,16 +715,16 @@ hisds hi_sdstrim(hisds s, const char *cset) {
* The string is modified in-place.
*
* Return value:
- * -1 (error) if hi_sdslen(s) is larger than maximum positive ssize_t value.
+ * -1 (error) if sdslen(s) is larger than maximum positive ssize_t value.
* 0 on success.
*
* Example:
*
- * s = hi_sdsnew("Hello World");
- * hi_sdsrange(s,1,-1); => "ello World"
+ * s = sdsnew("Hello World");
+ * sdsrange(s,1,-1); => "ello World"
*/
-int hi_sdsrange(hisds s, ssize_t start, ssize_t end) {
- size_t newlen, len = hi_sdslen(s);
+int sdsrange(sds s, ssize_t start, ssize_t end) {
+ size_t newlen, len = sdslen(s);
if (len > SSIZE_MAX) return -1;
if (len == 0) return 0;
@@ -749,25 +749,25 @@ int hi_sdsrange(hisds s, ssize_t start, ssize_t end) {
}
if (start && newlen) memmove(s, s+start, newlen);
s[newlen] = 0;
- hi_sdssetlen(s,newlen);
+ sdssetlen(s,newlen);
return 0;
}
-/* Apply tolower() to every character of the hisds string 's'. */
-void hi_sdstolower(hisds s) {
- int len = hi_sdslen(s), j;
+/* Apply tolower() to every character of the sds string 's'. */
+void sdstolower(sds s) {
+ int len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
}
-/* Apply toupper() to every character of the hisds string 's'. */
-void hi_sdstoupper(hisds s) {
- int len = hi_sdslen(s), j;
+/* Apply toupper() to every character of the sds string 's'. */
+void sdstoupper(sds s) {
+ int len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
}
-/* Compare two hisds strings s1 and s2 with memcmp().
+/* Compare two sds strings s1 and s2 with memcmp().
*
* Return value:
*
@@ -778,12 +778,12 @@ void hi_sdstoupper(hisds s) {
* If two strings share exactly the same prefix, but one of the two has
* additional characters, the longer string is considered to be greater than
* the smaller one. */
-int hi_sdscmp(const hisds s1, const hisds s2) {
+int sdscmp(const sds s1, const sds s2) {
size_t l1, l2, minlen;
int cmp;
- l1 = hi_sdslen(s1);
- l2 = hi_sdslen(s2);
+ l1 = sdslen(s1);
+ l2 = sdslen(s2);
minlen = (l1 < l2) ? l1 : l2;
cmp = memcmp(s1,s2,minlen);
if (cmp == 0) return l1-l2;
@@ -791,7 +791,7 @@ int hi_sdscmp(const hisds s1, const hisds s2) {
}
/* Split 's' with separator in 'sep'. An array
- * of hisds strings is returned. *count will be set
+ * of sds strings is returned. *count will be set
* by reference to the number of tokens returned.
*
* On out of memory, zero length string, zero length
@@ -799,20 +799,20 @@ int hi_sdscmp(const hisds s1, const hisds s2) {
*
* Note that 'sep' is able to split a string using
* a multi-character separator. For example
- * hi_sdssplit("foo_-_bar","_-_"); will return two
+ * sdssplit("foo_-_bar","_-_"); will return two
* elements "foo" and "bar".
*
* This version of the function is binary-safe but
- * requires length arguments. hi_sdssplit() is just the
+ * requires length arguments. sdssplit() is just the
* same function but for zero-terminated strings.
*/
-hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
+sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
int elements = 0, slots = 5, start = 0, j;
- hisds *tokens;
+ sds *tokens;
if (seplen < 1 || len < 0) return NULL;
- tokens = hi_s_malloc(sizeof(hisds)*slots);
+ tokens = s_malloc(sizeof(sds)*slots);
if (tokens == NULL) return NULL;
if (len == 0) {
@@ -822,16 +822,16 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
for (j = 0; j < (len-(seplen-1)); j++) {
/* make sure there is room for the next element and the final one */
if (slots < elements+2) {
- hisds *newtokens;
+ sds *newtokens;
slots *= 2;
- newtokens = hi_s_realloc(tokens,sizeof(hisds)*slots);
+ newtokens = s_realloc(tokens,sizeof(sds)*slots);
if (newtokens == NULL) goto cleanup;
tokens = newtokens;
}
/* search the separator */
if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
- tokens[elements] = hi_sdsnewlen(s+start,j-start);
+ tokens[elements] = sdsnewlen(s+start,j-start);
if (tokens[elements] == NULL) goto cleanup;
elements++;
start = j+seplen;
@@ -839,7 +839,7 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
}
}
/* Add the final element. We are sure there is room in the tokens array. */
- tokens[elements] = hi_sdsnewlen(s+start,len-start);
+ tokens[elements] = sdsnewlen(s+start,len-start);
if (tokens[elements] == NULL) goto cleanup;
elements++;
*count = elements;
@@ -848,55 +848,55 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
cleanup:
{
int i;
- for (i = 0; i < elements; i++) hi_sdsfree(tokens[i]);
- hi_s_free(tokens);
+ for (i = 0; i < elements; i++) sdsfree(tokens[i]);
+ s_free(tokens);
*count = 0;
return NULL;
}
}
-/* Free the result returned by hi_sdssplitlen(), or do nothing if 'tokens' is NULL. */
-void hi_sdsfreesplitres(hisds *tokens, int count) {
+/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
+void sdsfreesplitres(sds *tokens, int count) {
if (!tokens) return;
while(count--)
- hi_sdsfree(tokens[count]);
- hi_s_free(tokens);
+ sdsfree(tokens[count]);
+ s_free(tokens);
}
-/* Append to the hisds string "s" an escaped string representation where
+/* Append to the sds string "s" an escaped string representation where
* all the non-printable characters (tested with isprint()) are turned into
* escapes in the form "\n\r\a...." or "\x<hex-number>".
*
- * After the call, the modified hisds string is no longer valid and all the
+ * After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
-hisds hi_sdscatrepr(hisds s, const char *p, size_t len) {
- s = hi_sdscatlen(s,"\"",1);
+sds sdscatrepr(sds s, const char *p, size_t len) {
+ s = sdscatlen(s,"\"",1);
while(len--) {
switch(*p) {
case '\\':
case '"':
- s = hi_sdscatprintf(s,"\\%c",*p);
+ s = sdscatprintf(s,"\\%c",*p);
break;
- case '\n': s = hi_sdscatlen(s,"\\n",2); break;
- case '\r': s = hi_sdscatlen(s,"\\r",2); break;
- case '\t': s = hi_sdscatlen(s,"\\t",2); break;
- case '\a': s = hi_sdscatlen(s,"\\a",2); break;
- case '\b': s = hi_sdscatlen(s,"\\b",2); break;
+ case '\n': s = sdscatlen(s,"\\n",2); break;
+ case '\r': s = sdscatlen(s,"\\r",2); break;
+ case '\t': s = sdscatlen(s,"\\t",2); break;
+ case '\a': s = sdscatlen(s,"\\a",2); break;
+ case '\b': s = sdscatlen(s,"\\b",2); break;
default:
if (isprint(*p))
- s = hi_sdscatprintf(s,"%c",*p);
+ s = sdscatprintf(s,"%c",*p);
else
- s = hi_sdscatprintf(s,"\\x%02x",(unsigned char)*p);
+ s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
break;
}
p++;
}
- return hi_sdscatlen(s,"\"",1);
+ return sdscatlen(s,"\"",1);
}
-/* Helper function for hi_sdssplitargs() that converts a hex digit into an
+/* Helper function for sdssplitargs() that converts a hex digit into an
* integer from 0 to 15 */
-static int hi_hex_digit_to_int(char c) {
+int hex_digit_to_int(char c) {
switch(c) {
case '0': return 0;
case '1': return 1;
@@ -924,20 +924,20 @@ static int hi_hex_digit_to_int(char c) {
* foo bar "newline are supported\n" and "\xff\x00otherstuff"
*
* The number of arguments is stored into *argc, and an array
- * of hisds is returned.
+ * of sds is returned.
*
- * The caller should free the resulting array of hisds strings with
- * hi_sdsfreesplitres().
+ * The caller should free the resulting array of sds strings with
+ * sdsfreesplitres().
*
- * Note that hi_sdscatrepr() is able to convert back a string into
- * a quoted string in the same format hi_sdssplitargs() is able to parse.
+ * Note that sdscatrepr() is able to convert back a string into
+ * a quoted string in the same format sdssplitargs() is able to parse.
*
* The function returns the allocated tokens on success, even when the
* input string is empty, or NULL if the input contains unbalanced
* quotes or closed quotes followed by non space characters
* as in: "foo"bar or "foo'
*/
-hisds *hi_sdssplitargs(const char *line, int *argc) {
+sds *sdssplitargs(const char *line, int *argc) {
const char *p = line;
char *current = NULL;
char **vector = NULL;
@@ -952,7 +952,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
int insq=0; /* set to 1 if we are in 'single quotes' */
int done=0;
- if (current == NULL) current = hi_sdsempty();
+ if (current == NULL) current = sdsempty();
while(!done) {
if (inq) {
if (*p == '\\' && *(p+1) == 'x' &&
@@ -961,9 +961,9 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
{
unsigned char byte;
- byte = (hi_hex_digit_to_int(*(p+2))*16)+
- hi_hex_digit_to_int(*(p+3));
- current = hi_sdscatlen(current,(char*)&byte,1);
+ byte = (hex_digit_to_int(*(p+2))*16)+
+ hex_digit_to_int(*(p+3));
+ current = sdscatlen(current,(char*)&byte,1);
p += 3;
} else if (*p == '\\' && *(p+1)) {
char c;
@@ -977,7 +977,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
case 'a': c = '\a'; break;
default: c = *p; break;
}
- current = hi_sdscatlen(current,&c,1);
+ current = sdscatlen(current,&c,1);
} else if (*p == '"') {
/* closing quote must be followed by a space or
* nothing at all. */
@@ -987,12 +987,12 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
/* unterminated quotes */
goto err;
} else {
- current = hi_sdscatlen(current,p,1);
+ current = sdscatlen(current,p,1);
}
} else if (insq) {
if (*p == '\\' && *(p+1) == '\'') {
p++;
- current = hi_sdscatlen(current,"'",1);
+ current = sdscatlen(current,"'",1);
} else if (*p == '\'') {
/* closing quote must be followed by a space or
* nothing at all. */
@@ -1002,7 +1002,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
/* unterminated quotes */
goto err;
} else {
- current = hi_sdscatlen(current,p,1);
+ current = sdscatlen(current,p,1);
}
} else {
switch(*p) {
@@ -1020,7 +1020,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
insq=1;
break;
default:
- current = hi_sdscatlen(current,p,1);
+ current = sdscatlen(current,p,1);
break;
}
}
@@ -1028,9 +1028,9 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
}
/* add the token to the vector */
{
- char **new_vector = hi_s_realloc(vector,((*argc)+1)*sizeof(char*));
+ char **new_vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
if (new_vector == NULL) {
- hi_s_free(vector);
+ s_free(vector);
return NULL;
}
@@ -1041,16 +1041,16 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
}
} else {
/* Even on empty input string return something not NULL. */
- if (vector == NULL) vector = hi_s_malloc(sizeof(void*));
+ if (vector == NULL) vector = s_malloc(sizeof(void*));
return vector;
}
}
err:
while((*argc)--)
- hi_sdsfree(vector[*argc]);
- hi_s_free(vector);
- if (current) hi_sdsfree(current);
+ sdsfree(vector[*argc]);
+ s_free(vector);
+ if (current) sdsfree(current);
*argc = 0;
return NULL;
}
@@ -1059,13 +1059,13 @@ err:
* characters specified in the 'from' string to the corresponding character
* in the 'to' array.
*
- * For instance: hi_sdsmapchars(mystring, "ho", "01", 2)
+ * For instance: sdsmapchars(mystring, "ho", "01", 2)
* will have the effect of turning the string "hello" into "0ell1".
*
- * The function returns the hisds string pointer, that is always the same
+ * The function returns the sds string pointer, that is always the same
* as the input pointer since no resize is needed. */
-hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen) {
- size_t j, i, l = hi_sdslen(s);
+sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
+ size_t j, i, l = sdslen(s);
for (j = 0; j < l; j++) {
for (i = 0; i < setlen; i++) {
@@ -1079,26 +1079,26 @@ hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen) {
}
/* Join an array of C strings using the specified separator (also a C string).
- * Returns the result as an hisds string. */
-hisds hi_sdsjoin(char **argv, int argc, char *sep) {
- hisds join = hi_sdsempty();
+ * Returns the result as an sds string. */
+sds sdsjoin(char **argv, int argc, char *sep) {
+ sds join = sdsempty();
int j;
for (j = 0; j < argc; j++) {
- join = hi_sdscat(join, argv[j]);
- if (j != argc-1) join = hi_sdscat(join,sep);
+ join = sdscat(join, argv[j]);
+ if (j != argc-1) join = sdscat(join,sep);
}
return join;
}
-/* Like hi_sdsjoin, but joins an array of SDS strings. */
-hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen) {
- hisds join = hi_sdsempty();
+/* Like sdsjoin, but joins an array of SDS strings. */
+sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
+ sds join = sdsempty();
int j;
for (j = 0; j < argc; j++) {
- join = hi_sdscatsds(join, argv[j]);
- if (j != argc-1) join = hi_sdscatlen(join,sep,seplen);
+ join = sdscatsds(join, argv[j]);
+ if (j != argc-1) join = sdscatlen(join,sep,seplen);
}
return join;
}
@@ -1108,138 +1108,138 @@ hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen) {
* the overhead of function calls. Here we define these wrappers only for
* the programs SDS is linked to, if they want to touch the SDS internals
* even if they use a different allocator. */
-void *hi_sds_malloc(size_t size) { return hi_s_malloc(size); }
-void *hi_sds_realloc(void *ptr, size_t size) { return hi_s_realloc(ptr,size); }
-void hi_sds_free(void *ptr) { hi_s_free(ptr); }
+void *sds_malloc(size_t size) { return s_malloc(size); }
+void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); }
+void sds_free(void *ptr) { s_free(ptr); }
-#if defined(HI_SDS_TEST_MAIN)
+#if defined(SDS_TEST_MAIN)
#include <stdio.h>
#include "testhelp.h"
#include "limits.h"
#define UNUSED(x) (void)(x)
-int hi_sdsTest(void) {
+int sdsTest(void) {
{
- hisds x = hi_sdsnew("foo"), y;
+ sds x = sdsnew("foo"), y;
test_cond("Create a string and obtain the length",
- hi_sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
+ sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
- hi_sdsfree(x);
- x = hi_sdsnewlen("foo",2);
+ sdsfree(x);
+ x = sdsnewlen("foo",2);
test_cond("Create a string with specified length",
- hi_sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
+ sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
- x = hi_sdscat(x,"bar");
+ x = sdscat(x,"bar");
test_cond("Strings concatenation",
- hi_sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
+ sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
- x = hi_sdscpy(x,"a");
- test_cond("hi_sdscpy() against an originally longer string",
- hi_sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
+ x = sdscpy(x,"a");
+ test_cond("sdscpy() against an originally longer string",
+ sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
- x = hi_sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
- test_cond("hi_sdscpy() against an originally shorter string",
- hi_sdslen(x) == 33 &&
+ x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
+ test_cond("sdscpy() against an originally shorter string",
+ sdslen(x) == 33 &&
memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
- hi_sdsfree(x);
- x = hi_sdscatprintf(hi_sdsempty(),"%d",123);
- test_cond("hi_sdscatprintf() seems working in the base case",
- hi_sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
+ sdsfree(x);
+ x = sdscatprintf(sdsempty(),"%d",123);
+ test_cond("sdscatprintf() seems working in the base case",
+ sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
- hi_sdsfree(x);
- x = hi_sdsnew("--");
- x = hi_sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
- test_cond("hi_sdscatfmt() seems working in the base case",
- hi_sdslen(x) == 60 &&
+ sdsfree(x);
+ x = sdsnew("--");
+ x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
+ test_cond("sdscatfmt() seems working in the base case",
+ sdslen(x) == 60 &&
memcmp(x,"--Hello Hi! World -9223372036854775808,"
"9223372036854775807--",60) == 0)
printf("[%s]\n",x);
- hi_sdsfree(x);
- x = hi_sdsnew("--");
- x = hi_sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
- test_cond("hi_sdscatfmt() seems working with unsigned numbers",
- hi_sdslen(x) == 35 &&
+ sdsfree(x);
+ x = sdsnew("--");
+ x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
+ test_cond("sdscatfmt() seems working with unsigned numbers",
+ sdslen(x) == 35 &&
memcmp(x,"--4294967295,18446744073709551615--",35) == 0)
- hi_sdsfree(x);
- x = hi_sdsnew(" x ");
- hi_sdstrim(x," x");
- test_cond("hi_sdstrim() works when all chars match",
- hi_sdslen(x) == 0)
-
- hi_sdsfree(x);
- x = hi_sdsnew(" x ");
- hi_sdstrim(x," ");
- test_cond("hi_sdstrim() works when a single char remains",
- hi_sdslen(x) == 1 && x[0] == 'x')
-
- hi_sdsfree(x);
- x = hi_sdsnew("xxciaoyyy");
- hi_sdstrim(x,"xy");
- test_cond("hi_sdstrim() correctly trims characters",
- hi_sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
-
- y = hi_sdsdup(x);
- hi_sdsrange(y,1,1);
- test_cond("hi_sdsrange(...,1,1)",
- hi_sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
-
- hi_sdsfree(y);
- y = hi_sdsdup(x);
- hi_sdsrange(y,1,-1);
- test_cond("hi_sdsrange(...,1,-1)",
- hi_sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
-
- hi_sdsfree(y);
- y = hi_sdsdup(x);
- hi_sdsrange(y,-2,-1);
- test_cond("hi_sdsrange(...,-2,-1)",
- hi_sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
-
- hi_sdsfree(y);
- y = hi_sdsdup(x);
- hi_sdsrange(y,2,1);
- test_cond("hi_sdsrange(...,2,1)",
- hi_sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
-
- hi_sdsfree(y);
- y = hi_sdsdup(x);
- hi_sdsrange(y,1,100);
- test_cond("hi_sdsrange(...,1,100)",
- hi_sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
-
- hi_sdsfree(y);
- y = hi_sdsdup(x);
- hi_sdsrange(y,100,100);
- test_cond("hi_sdsrange(...,100,100)",
- hi_sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
-
- hi_sdsfree(y);
- hi_sdsfree(x);
- x = hi_sdsnew("foo");
- y = hi_sdsnew("foa");
- test_cond("hi_sdscmp(foo,foa)", hi_sdscmp(x,y) > 0)
-
- hi_sdsfree(y);
- hi_sdsfree(x);
- x = hi_sdsnew("bar");
- y = hi_sdsnew("bar");
- test_cond("hi_sdscmp(bar,bar)", hi_sdscmp(x,y) == 0)
-
- hi_sdsfree(y);
- hi_sdsfree(x);
- x = hi_sdsnew("aar");
- y = hi_sdsnew("bar");
- test_cond("hi_sdscmp(bar,bar)", hi_sdscmp(x,y) < 0)
-
- hi_sdsfree(y);
- hi_sdsfree(x);
- x = hi_sdsnewlen("\a\n\0foo\r",7);
- y = hi_sdscatrepr(hi_sdsempty(),x,hi_sdslen(x));
- test_cond("hi_sdscatrepr(...data...)",
+ sdsfree(x);
+ x = sdsnew(" x ");
+ sdstrim(x," x");
+ test_cond("sdstrim() works when all chars match",
+ sdslen(x) == 0)
+
+ sdsfree(x);
+ x = sdsnew(" x ");
+ sdstrim(x," ");
+ test_cond("sdstrim() works when a single char remains",
+ sdslen(x) == 1 && x[0] == 'x')
+
+ sdsfree(x);
+ x = sdsnew("xxciaoyyy");
+ sdstrim(x,"xy");
+ test_cond("sdstrim() correctly trims characters",
+ sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
+
+ y = sdsdup(x);
+ sdsrange(y,1,1);
+ test_cond("sdsrange(...,1,1)",
+ sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,1,-1);
+ test_cond("sdsrange(...,1,-1)",
+ sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,-2,-1);
+ test_cond("sdsrange(...,-2,-1)",
+ sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,2,1);
+ test_cond("sdsrange(...,2,1)",
+ sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,1,100);
+ test_cond("sdsrange(...,1,100)",
+ sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,100,100);
+ test_cond("sdsrange(...,100,100)",
+ sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("foo");
+ y = sdsnew("foa");
+ test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("bar");
+ y = sdsnew("bar");
+ test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("aar");
+ y = sdsnew("bar");
+ test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnewlen("\a\n\0foo\r",7);
+ y = sdscatrepr(sdsempty(),x,sdslen(x));
+ test_cond("sdscatrepr(...data...)",
memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
{
@@ -1247,43 +1247,43 @@ int hi_sdsTest(void) {
char *p;
int step = 10, j, i;
- hi_sdsfree(x);
- hi_sdsfree(y);
- x = hi_sdsnew("0");
- test_cond("hi_sdsnew() free/len buffers", hi_sdslen(x) == 1 && hi_sdsavail(x) == 0);
+ sdsfree(x);
+ sdsfree(y);
+ x = sdsnew("0");
+ test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0);
/* Run the test a few times in order to hit the first two
* SDS header types. */
for (i = 0; i < 10; i++) {
- int oldlen = hi_sdslen(x);
- x = hi_sdsMakeRoomFor(x,step);
- int type = x[-1]&HI_SDS_TYPE_MASK;
-
- test_cond("sdsMakeRoomFor() len", hi_sdslen(x) == oldlen);
- if (type != HI_SDS_TYPE_5) {
- test_cond("hi_sdsMakeRoomFor() free", hi_sdsavail(x) >= step);
- oldfree = hi_sdsavail(x);
+ int oldlen = sdslen(x);
+ x = sdsMakeRoomFor(x,step);
+ int type = x[-1]&SDS_TYPE_MASK;
+
+ test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
+ if (type != SDS_TYPE_5) {
+ test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
+ oldfree = sdsavail(x);
}
p = x+oldlen;
for (j = 0; j < step; j++) {
p[j] = 'A'+j;
}
- hi_sdsIncrLen(x,step);
+ sdsIncrLen(x,step);
}
- test_cond("hi_sdsMakeRoomFor() content",
+ test_cond("sdsMakeRoomFor() content",
memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0);
- test_cond("sdsMakeRoomFor() final length",hi_sdslen(x)==101);
+ test_cond("sdsMakeRoomFor() final length",sdslen(x)==101);
- hi_sdsfree(x);
+ sdsfree(x);
}
}
- test_report();
+ test_report()
return 0;
}
#endif
-#ifdef HI_SDS_TEST_MAIN
+#ifdef SDS_TEST_MAIN
int main(void) {
- return hi_sdsTest();
+ return sdsTest();
}
#endif
diff --git a/deps/hiredis/sds.h b/deps/hiredis/sds.h
index 573d6dd19..eda8833b5 100644
--- a/deps/hiredis/sds.h
+++ b/deps/hiredis/sds.h
@@ -30,10 +30,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HIREDIS_SDS_H
-#define HIREDIS_SDS_H
+#ifndef __SDS_H
+#define __SDS_H
-#define HI_SDS_MAX_PREALLOC (1024*1024)
+#define SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER
#define __attribute__(x)
typedef long long ssize_t;
@@ -44,235 +44,235 @@ typedef long long ssize_t;
#include <stdarg.h>
#include <stdint.h>
-typedef char *hisds;
+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__)) hisdshdr5 {
+struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
-struct __attribute__ ((__packed__)) hisdshdr8 {
+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__)) hisdshdr16 {
+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__)) hisdshdr32 {
+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__)) hisdshdr64 {
+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 HI_SDS_TYPE_5 0
-#define HI_SDS_TYPE_8 1
-#define HI_SDS_TYPE_16 2
-#define HI_SDS_TYPE_32 3
-#define HI_SDS_TYPE_64 4
-#define HI_SDS_TYPE_MASK 7
-#define HI_SDS_TYPE_BITS 3
-#define HI_SDS_HDR_VAR(T,s) struct hisdshdr##T *sh = (struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T)));
-#define HI_SDS_HDR(T,s) ((struct hisdshdr##T *)((s)-(sizeof(struct hisdshdr##T))))
-#define HI_SDS_TYPE_5_LEN(f) ((f)>>HI_SDS_TYPE_BITS)
+#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 hi_sdslen(const hisds s) {
+static inline size_t sdslen(const sds s) {
unsigned char flags = s[-1];
- switch(flags & HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5:
- return HI_SDS_TYPE_5_LEN(flags);
- case HI_SDS_TYPE_8:
- return HI_SDS_HDR(8,s)->len;
- case HI_SDS_TYPE_16:
- return HI_SDS_HDR(16,s)->len;
- case HI_SDS_TYPE_32:
- return HI_SDS_HDR(32,s)->len;
- case HI_SDS_TYPE_64:
- return HI_SDS_HDR(64,s)->len;
+ 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 hi_sdsavail(const hisds s) {
+static inline size_t sdsavail(const sds s) {
unsigned char flags = s[-1];
- switch(flags&HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5: {
+ switch(flags&SDS_TYPE_MASK) {
+ case SDS_TYPE_5: {
return 0;
}
- case HI_SDS_TYPE_8: {
- HI_SDS_HDR_VAR(8,s);
+ case SDS_TYPE_8: {
+ SDS_HDR_VAR(8,s);
return sh->alloc - sh->len;
}
- case HI_SDS_TYPE_16: {
- HI_SDS_HDR_VAR(16,s);
+ case SDS_TYPE_16: {
+ SDS_HDR_VAR(16,s);
return sh->alloc - sh->len;
}
- case HI_SDS_TYPE_32: {
- HI_SDS_HDR_VAR(32,s);
+ case SDS_TYPE_32: {
+ SDS_HDR_VAR(32,s);
return sh->alloc - sh->len;
}
- case HI_SDS_TYPE_64: {
- HI_SDS_HDR_VAR(64,s);
+ case SDS_TYPE_64: {
+ SDS_HDR_VAR(64,s);
return sh->alloc - sh->len;
}
}
return 0;
}
-static inline void hi_sdssetlen(hisds s, size_t newlen) {
+static inline void sdssetlen(sds s, size_t newlen) {
unsigned char flags = s[-1];
- switch(flags&HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5:
+ switch(flags&SDS_TYPE_MASK) {
+ case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
- *fp = (unsigned char)(HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS));
+ *fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
}
break;
- case HI_SDS_TYPE_8:
- HI_SDS_HDR(8,s)->len = (uint8_t)newlen;
+ case SDS_TYPE_8:
+ SDS_HDR(8,s)->len = (uint8_t)newlen;
break;
- case HI_SDS_TYPE_16:
- HI_SDS_HDR(16,s)->len = (uint16_t)newlen;
+ case SDS_TYPE_16:
+ SDS_HDR(16,s)->len = (uint16_t)newlen;
break;
- case HI_SDS_TYPE_32:
- HI_SDS_HDR(32,s)->len = (uint32_t)newlen;
+ case SDS_TYPE_32:
+ SDS_HDR(32,s)->len = (uint32_t)newlen;
break;
- case HI_SDS_TYPE_64:
- HI_SDS_HDR(64,s)->len = (uint64_t)newlen;
+ case SDS_TYPE_64:
+ SDS_HDR(64,s)->len = (uint64_t)newlen;
break;
}
}
-static inline void hi_sdsinclen(hisds s, size_t inc) {
+static inline void sdsinclen(sds s, size_t inc) {
unsigned char flags = s[-1];
- switch(flags&HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5:
+ switch(flags&SDS_TYPE_MASK) {
+ case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
- unsigned char newlen = HI_SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
- *fp = HI_SDS_TYPE_5 | (newlen << HI_SDS_TYPE_BITS);
+ unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
+ *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
}
break;
- case HI_SDS_TYPE_8:
- HI_SDS_HDR(8,s)->len += (uint8_t)inc;
+ case SDS_TYPE_8:
+ SDS_HDR(8,s)->len += (uint8_t)inc;
break;
- case HI_SDS_TYPE_16:
- HI_SDS_HDR(16,s)->len += (uint16_t)inc;
+ case SDS_TYPE_16:
+ SDS_HDR(16,s)->len += (uint16_t)inc;
break;
- case HI_SDS_TYPE_32:
- HI_SDS_HDR(32,s)->len += (uint32_t)inc;
+ case SDS_TYPE_32:
+ SDS_HDR(32,s)->len += (uint32_t)inc;
break;
- case HI_SDS_TYPE_64:
- HI_SDS_HDR(64,s)->len += (uint64_t)inc;
+ case SDS_TYPE_64:
+ SDS_HDR(64,s)->len += (uint64_t)inc;
break;
}
}
-/* hi_sdsalloc() = hi_sdsavail() + hi_sdslen() */
-static inline size_t hi_sdsalloc(const hisds s) {
+/* sdsalloc() = sdsavail() + sdslen() */
+static inline size_t sdsalloc(const sds s) {
unsigned char flags = s[-1];
- switch(flags & HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5:
- return HI_SDS_TYPE_5_LEN(flags);
- case HI_SDS_TYPE_8:
- return HI_SDS_HDR(8,s)->alloc;
- case HI_SDS_TYPE_16:
- return HI_SDS_HDR(16,s)->alloc;
- case HI_SDS_TYPE_32:
- return HI_SDS_HDR(32,s)->alloc;
- case HI_SDS_TYPE_64:
- return HI_SDS_HDR(64,s)->alloc;
+ 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 hi_sdssetalloc(hisds s, size_t newlen) {
+static inline void sdssetalloc(sds s, size_t newlen) {
unsigned char flags = s[-1];
- switch(flags&HI_SDS_TYPE_MASK) {
- case HI_SDS_TYPE_5:
+ switch(flags&SDS_TYPE_MASK) {
+ case SDS_TYPE_5:
/* Nothing to do, this type has no total allocation info. */
break;
- case HI_SDS_TYPE_8:
- HI_SDS_HDR(8,s)->alloc = (uint8_t)newlen;
+ case SDS_TYPE_8:
+ SDS_HDR(8,s)->alloc = (uint8_t)newlen;
break;
- case HI_SDS_TYPE_16:
- HI_SDS_HDR(16,s)->alloc = (uint16_t)newlen;
+ case SDS_TYPE_16:
+ SDS_HDR(16,s)->alloc = (uint16_t)newlen;
break;
- case HI_SDS_TYPE_32:
- HI_SDS_HDR(32,s)->alloc = (uint32_t)newlen;
+ case SDS_TYPE_32:
+ SDS_HDR(32,s)->alloc = (uint32_t)newlen;
break;
- case HI_SDS_TYPE_64:
- HI_SDS_HDR(64,s)->alloc = (uint64_t)newlen;
+ case SDS_TYPE_64:
+ SDS_HDR(64,s)->alloc = (uint64_t)newlen;
break;
}
}
-hisds hi_sdsnewlen(const void *init, size_t initlen);
-hisds hi_sdsnew(const char *init);
-hisds hi_sdsempty(void);
-hisds hi_sdsdup(const hisds s);
-void hi_sdsfree(hisds s);
-hisds hi_sdsgrowzero(hisds s, size_t len);
-hisds hi_sdscatlen(hisds s, const void *t, size_t len);
-hisds hi_sdscat(hisds s, const char *t);
-hisds hi_sdscatsds(hisds s, const hisds t);
-hisds hi_sdscpylen(hisds s, const char *t, size_t len);
-hisds hi_sdscpy(hisds s, const char *t);
+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);
-hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap);
+sds sdscatvprintf(sds s, const char *fmt, va_list ap);
#ifdef __GNUC__
-hisds hi_sdscatprintf(hisds s, const char *fmt, ...)
+sds sdscatprintf(sds s, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#else
-hisds hi_sdscatprintf(hisds s, const char *fmt, ...);
+sds sdscatprintf(sds s, const char *fmt, ...);
#endif
-hisds hi_sdscatfmt(hisds s, char const *fmt, ...);
-hisds hi_sdstrim(hisds s, const char *cset);
-int hi_sdsrange(hisds s, ssize_t start, ssize_t end);
-void hi_sdsupdatelen(hisds s);
-void hi_sdsclear(hisds s);
-int hi_sdscmp(const hisds s1, const hisds s2);
-hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
-void hi_sdsfreesplitres(hisds *tokens, int count);
-void hi_sdstolower(hisds s);
-void hi_sdstoupper(hisds s);
-hisds hi_sdsfromlonglong(long long value);
-hisds hi_sdscatrepr(hisds s, const char *p, size_t len);
-hisds *hi_sdssplitargs(const char *line, int *argc);
-hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen);
-hisds hi_sdsjoin(char **argv, int argc, char *sep);
-hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen);
+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 */
-hisds hi_sdsMakeRoomFor(hisds s, size_t addlen);
-void hi_sdsIncrLen(hisds s, int incr);
-hisds hi_sdsRemoveFreeSpace(hisds s);
-size_t hi_sdsAllocSize(hisds s);
-void *hi_sdsAllocPtr(hisds s);
+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 *hi_sds_malloc(size_t size);
-void *hi_sds_realloc(void *ptr, size_t size);
-void hi_sds_free(void *ptr);
+void *sds_malloc(size_t size);
+void *sds_realloc(void *ptr, size_t size);
+void sds_free(void *ptr);
#ifdef REDIS_TEST
-int hi_sdsTest(int argc, char *argv[]);
+int sdsTest(int argc, char *argv[]);
#endif
-#endif /* HIREDIS_SDS_H */
+#endif
diff --git a/deps/hiredis/sdsalloc.h b/deps/hiredis/sdsalloc.h
index c9dcc3df8..5538dd94c 100644
--- a/deps/hiredis/sdsalloc.h
+++ b/deps/hiredis/sdsalloc.h
@@ -39,6 +39,6 @@
#include "alloc.h"
-#define hi_s_malloc hi_malloc
-#define hi_s_realloc hi_realloc
-#define hi_s_free hi_free
+#define s_malloc hi_malloc
+#define s_realloc hi_realloc
+#define s_free hi_free
diff --git a/deps/hiredis/sdscompat.h b/deps/hiredis/sdscompat.h
deleted file mode 100644
index e5a2574f3..000000000
--- a/deps/hiredis/sdscompat.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * SDS compatibility header.
- *
- * This simple file maps sds types and calls to their unique hiredis symbol names.
- * It's useful when we build Hiredis as a dependency of Redis and want to call
- * Hiredis' sds symbols rather than the ones built into Redis, as the libraries
- * have slightly diverged and could cause hard to track down ABI incompatibility
- * bugs.
- *
- */
-
-#ifndef HIREDIS_SDS_COMPAT
-#define HIREDIS_SDS_COMPAT
-
-#define sds hisds
-
-#define sdslen hi_sdslen
-#define sdsavail hi_sdsavail
-#define sdssetlen hi_sdssetlen
-#define sdsinclen hi_sdsinclen
-#define sdsalloc hi_sdsalloc
-#define sdssetalloc hi_sdssetalloc
-
-#define sdsAllocPtr hi_sdsAllocPtr
-#define sdsAllocSize hi_sdsAllocSize
-#define sdscat hi_sdscat
-#define sdscatfmt hi_sdscatfmt
-#define sdscatlen hi_sdscatlen
-#define sdscatprintf hi_sdscatprintf
-#define sdscatrepr hi_sdscatrepr
-#define sdscatsds hi_sdscatsds
-#define sdscatvprintf hi_sdscatvprintf
-#define sdsclear hi_sdsclear
-#define sdscmp hi_sdscmp
-#define sdscpy hi_sdscpy
-#define sdscpylen hi_sdscpylen
-#define sdsdup hi_sdsdup
-#define sdsempty hi_sdsempty
-#define sds_free hi_sds_free
-#define sdsfree hi_sdsfree
-#define sdsfreesplitres hi_sdsfreesplitres
-#define sdsfromlonglong hi_sdsfromlonglong
-#define sdsgrowzero hi_sdsgrowzero
-#define sdsIncrLen hi_sdsIncrLen
-#define sdsjoin hi_sdsjoin
-#define sdsjoinsds hi_sdsjoinsds
-#define sdsll2str hi_sdsll2str
-#define sdsMakeRoomFor hi_sdsMakeRoomFor
-#define sds_malloc hi_sds_malloc
-#define sdsmapchars hi_sdsmapchars
-#define sdsnew hi_sdsnew
-#define sdsnewlen hi_sdsnewlen
-#define sdsrange hi_sdsrange
-#define sds_realloc hi_sds_realloc
-#define sdsRemoveFreeSpace hi_sdsRemoveFreeSpace
-#define sdssplitargs hi_sdssplitargs
-#define sdssplitlen hi_sdssplitlen
-#define sdstolower hi_sdstolower
-#define sdstoupper hi_sdstoupper
-#define sdstrim hi_sdstrim
-#define sdsull2str hi_sdsull2str
-#define sdsupdatelen hi_sdsupdatelen
-
-#endif /* HIREDIS_SDS_COMPAT */
diff --git a/deps/hiredis/ssl.c b/deps/hiredis/ssl.c
index fe9a2fdce..c581f63dc 100644
--- a/deps/hiredis/ssl.c
+++ b/deps/hiredis/ssl.c
@@ -38,6 +38,7 @@
#include <string.h>
#ifdef _WIN32
#include <windows.h>
+#include <wincrypt.h>
#else
#include <pthread.h>
#endif
@@ -182,6 +183,10 @@ const char *redisSSLContextGetError(redisSSLContextError error)
return "Failed to load client certificate";
case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED:
return "Failed to load private key";
+ case REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED:
+ return "Failed to open system certifcate store";
+ case REDIS_SSL_CTX_OS_CERT_ADD_FAILED:
+ return "Failed to add CA certificates obtained from system to the SSL context";
default:
return "Unknown error code";
}
@@ -214,6 +219,11 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
const char *cert_filename, const char *private_key_filename,
const char *server_name, redisSSLContextError *error)
{
+#ifdef _WIN32
+ HCERTSTORE win_store = NULL;
+ PCCERT_CONTEXT win_ctx = NULL;
+#endif
+
redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext));
if (ctx == NULL)
goto error;
@@ -234,6 +244,31 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
}
if (capath || cacert_filename) {
+#ifdef _WIN32
+ if (0 == strcmp(cacert_filename, "wincert")) {
+ win_store = CertOpenSystemStore(NULL, "Root");
+ if (!win_store) {
+ if (error) *error = REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED;
+ goto error;
+ }
+ X509_STORE* store = SSL_CTX_get_cert_store(ctx->ssl_ctx);
+ while (win_ctx = CertEnumCertificatesInStore(win_store, win_ctx)) {
+ X509* x509 = NULL;
+ x509 = d2i_X509(NULL, (const unsigned char**)&win_ctx->pbCertEncoded, win_ctx->cbCertEncoded);
+ if (x509) {
+ if ((1 != X509_STORE_add_cert(store, x509)) ||
+ (1 != SSL_CTX_add_client_CA(ctx->ssl_ctx, x509)))
+ {
+ if (error) *error = REDIS_SSL_CTX_OS_CERT_ADD_FAILED;
+ goto error;
+ }
+ X509_free(x509);
+ }
+ }
+ CertFreeCertificateContext(win_ctx);
+ CertCloseStore(win_store, 0);
+ } else
+#endif
if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) {
if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED;
goto error;
@@ -257,6 +292,10 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
return ctx;
error:
+#ifdef _WIN32
+ CertFreeCertificateContext(win_ctx);
+ CertCloseStore(win_store, 0);
+#endif
redisFreeSSLContext(ctx);
return NULL;
}
@@ -353,7 +392,11 @@ int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
}
}
- return redisSSLConnect(c, ssl);
+ if (redisSSLConnect(c, ssl) != REDIS_OK) {
+ goto error;
+ }
+
+ return REDIS_OK;
error:
if (ssl)
@@ -437,7 +480,7 @@ static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
static ssize_t redisSSLWrite(redisContext *c) {
redisSSL *rssl = c->privctx;
- size_t len = rssl->lastLen ? rssl->lastLen : hi_sdslen(c->obuf);
+ size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
int rv = SSL_write(rssl->ssl, c->obuf, len);
if (rv > 0) {
diff --git a/deps/hiredis/test.c b/deps/hiredis/test.c
index bdff74e88..f991ef1e7 100644
--- a/deps/hiredis/test.c
+++ b/deps/hiredis/test.c
@@ -11,12 +11,17 @@
#include <signal.h>
#include <errno.h>
#include <limits.h>
+#include <math.h>
#include "hiredis.h"
#include "async.h"
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#endif
+#ifdef HIREDIS_TEST_ASYNC
+#include "adapters/libevent.h"
+#include <event2/event.h>
+#endif
#include "net.h"
#include "win32.h"
@@ -58,6 +63,8 @@ struct pushCounters {
int str;
};
+static int insecure_calloc_calls;
+
#ifdef HIREDIS_TEST_SSL
redisSSLContext *_ssl_ctx = NULL;
#endif
@@ -345,21 +352,21 @@ static void test_format_commands(void) {
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
hi_free(cmd);
- hisds sds_cmd;
+ sds sds_cmd;
sds_cmd = NULL;
- test("Format command into hisds by passing argc/argv without lengths: ");
+ test("Format command into sds by passing argc/argv without lengths: ");
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL);
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
- hi_sdsfree(sds_cmd);
+ sdsfree(sds_cmd);
sds_cmd = NULL;
- test("Format command into hisds by passing argc/argv with lengths: ");
+ test("Format command into sds by passing argc/argv with lengths: ");
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens);
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
- hi_sdsfree(sds_cmd);
+ sdsfree(sds_cmd);
}
static void test_append_formatted_commands(struct config config) {
@@ -597,6 +604,147 @@ static void test_reply_reader(void) {
((redisReply*)reply)->element[1]->integer == 42);
freeReplyObject(reply);
redisReaderFree(reader);
+
+ test("Can parse RESP3 doubles: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, ",3.14159265358979323846\r\n",25);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_DOUBLE &&
+ fabs(((redisReply*)reply)->dval - 3.14159265358979323846) < 0.00000001 &&
+ ((redisReply*)reply)->len == 22 &&
+ strcmp(((redisReply*)reply)->str, "3.14159265358979323846") == 0);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Set error on invalid RESP3 double: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, ",3.14159\000265358979323846\r\n",26);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_ERR &&
+ strcasecmp(reader->errstr,"Bad double value") == 0);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Correctly parses RESP3 double INFINITY: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, ",inf\r\n",6);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_DOUBLE &&
+ isinf(((redisReply*)reply)->dval) &&
+ ((redisReply*)reply)->dval > 0);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Set error when RESP3 double is NaN: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, ",nan\r\n",6);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_ERR &&
+ strcasecmp(reader->errstr,"Bad double value") == 0);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Can parse RESP3 nil: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "_\r\n",3);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_NIL);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Set error on invalid RESP3 nil: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "_nil\r\n",6);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_ERR &&
+ strcasecmp(reader->errstr,"Bad nil value") == 0);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Can parse RESP3 bool (true): ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "#t\r\n",4);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_BOOL &&
+ ((redisReply*)reply)->integer);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Can parse RESP3 bool (false): ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "#f\r\n",4);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_BOOL &&
+ !((redisReply*)reply)->integer);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Set error on invalid RESP3 bool: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "#foobar\r\n",9);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_ERR &&
+ strcasecmp(reader->errstr,"Bad bool value") == 0);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Can parse RESP3 map: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "%2\r\n+first\r\n:123\r\n$6\r\nsecond\r\n#t\r\n",34);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_MAP &&
+ ((redisReply*)reply)->elements == 4 &&
+ ((redisReply*)reply)->element[0]->type == REDIS_REPLY_STATUS &&
+ ((redisReply*)reply)->element[0]->len == 5 &&
+ !strcmp(((redisReply*)reply)->element[0]->str,"first") &&
+ ((redisReply*)reply)->element[1]->type == REDIS_REPLY_INTEGER &&
+ ((redisReply*)reply)->element[1]->integer == 123 &&
+ ((redisReply*)reply)->element[2]->type == REDIS_REPLY_STRING &&
+ ((redisReply*)reply)->element[2]->len == 6 &&
+ !strcmp(((redisReply*)reply)->element[2]->str,"second") &&
+ ((redisReply*)reply)->element[3]->type == REDIS_REPLY_BOOL &&
+ ((redisReply*)reply)->element[3]->integer);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Can parse RESP3 set: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "~5\r\n+orange\r\n$5\r\napple\r\n#f\r\n:100\r\n:999\r\n",40);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_SET &&
+ ((redisReply*)reply)->elements == 5 &&
+ ((redisReply*)reply)->element[0]->type == REDIS_REPLY_STATUS &&
+ ((redisReply*)reply)->element[0]->len == 6 &&
+ !strcmp(((redisReply*)reply)->element[0]->str,"orange") &&
+ ((redisReply*)reply)->element[1]->type == REDIS_REPLY_STRING &&
+ ((redisReply*)reply)->element[1]->len == 5 &&
+ !strcmp(((redisReply*)reply)->element[1]->str,"apple") &&
+ ((redisReply*)reply)->element[2]->type == REDIS_REPLY_BOOL &&
+ !((redisReply*)reply)->element[2]->integer &&
+ ((redisReply*)reply)->element[3]->type == REDIS_REPLY_INTEGER &&
+ ((redisReply*)reply)->element[3]->integer == 100 &&
+ ((redisReply*)reply)->element[4]->type == REDIS_REPLY_INTEGER &&
+ ((redisReply*)reply)->element[4]->integer == 999);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
+ test("Can parse RESP3 bignum: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader,"(3492890328409238509324850943850943825024385\r\n",46);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_BIGNUM &&
+ ((redisReply*)reply)->len == 43 &&
+ !strcmp(((redisReply*)reply)->str,"3492890328409238509324850943850943825024385"));
+ freeReplyObject(reply);
+ redisReaderFree(reader);
}
static void test_free_null(void) {
@@ -623,6 +771,13 @@ static void *hi_calloc_fail(size_t nmemb, size_t size) {
return NULL;
}
+static void *hi_calloc_insecure(size_t nmemb, size_t size) {
+ (void)nmemb;
+ (void)size;
+ insecure_calloc_calls++;
+ return (void*)0xdeadc0de;
+}
+
static void *hi_realloc_fail(void *ptr, size_t size) {
(void)ptr;
(void)size;
@@ -630,6 +785,8 @@ static void *hi_realloc_fail(void *ptr, size_t size) {
}
static void test_allocator_injection(void) {
+ void *ptr;
+
hiredisAllocFuncs ha = {
.mallocFn = hi_malloc_fail,
.callocFn = hi_calloc_fail,
@@ -649,6 +806,13 @@ static void test_allocator_injection(void) {
redisReader *reader = redisReaderCreate();
test_cond(reader == NULL);
+ /* Make sure hiredis itself protects against a non-overflow checking calloc */
+ test("hiredis calloc wrapper protects against overflow: ");
+ ha.callocFn = hi_calloc_insecure;
+ hiredisSetAllocators(&ha);
+ ptr = hi_calloc((SIZE_MAX / sizeof(void*)) + 3, sizeof(void*));
+ test_cond(ptr == NULL && insecure_calloc_calls == 0);
+
// Return allocators to default
hiredisResetAllocators();
}
@@ -1283,6 +1447,440 @@ static void test_throughput(struct config config) {
// redisFree(c);
// }
+#ifdef HIREDIS_TEST_ASYNC
+struct event_base *base;
+
+typedef struct TestState {
+ redisOptions *options;
+ int checkpoint;
+ int resp3;
+ int disconnect;
+} TestState;
+
+/* Helper to disconnect and stop event loop */
+void async_disconnect(redisAsyncContext *ac) {
+ redisAsyncDisconnect(ac);
+ event_base_loopbreak(base);
+}
+
+/* Testcase timeout, will trigger a failure */
+void timeout_cb(int fd, short event, void *arg) {
+ (void) fd; (void) event; (void) arg;
+ printf("Timeout in async testing!\n");
+ exit(1);
+}
+
+/* Unexpected call, will trigger a failure */
+void unexpected_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ (void) ac; (void) r;
+ printf("Unexpected call: %s\n",(char*)privdata);
+ exit(1);
+}
+
+/* Helper function to publish a message via own client. */
+void publish_msg(redisOptions *options, const char* channel, const char* msg) {
+ redisContext *c = redisConnectWithOptions(options);
+ assert(c != NULL);
+ redisReply *reply = redisCommand(c,"PUBLISH %s %s",channel,msg);
+ assert(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1);
+ freeReplyObject(reply);
+ disconnect(c, 0);
+}
+
+/* Expect a reply of type INTEGER */
+void integer_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+ assert(reply != NULL && reply->type == REDIS_REPLY_INTEGER);
+ state->checkpoint++;
+ if (state->disconnect) async_disconnect(ac);
+}
+
+/* Subscribe callback for test_pubsub_handling and test_pubsub_handling_resp3:
+ * - a published message triggers an unsubscribe
+ * - a command is sent before the unsubscribe response is received. */
+void subscribe_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+
+ assert(reply != NULL &&
+ reply->type == (state->resp3 ? REDIS_REPLY_PUSH : REDIS_REPLY_ARRAY) &&
+ reply->elements == 3);
+
+ if (strcmp(reply->element[0]->str,"subscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
+ reply->element[2]->str == NULL);
+ publish_msg(state->options,"mychannel","Hello!");
+ } else if (strcmp(reply->element[0]->str,"message") == 0) {
+ assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
+ strcmp(reply->element[2]->str,"Hello!") == 0);
+ state->checkpoint++;
+
+ /* Unsubscribe after receiving the published message. Send unsubscribe
+ * which should call the callback registered during subscribe */
+ redisAsyncCommand(ac,unexpected_cb,
+ (void*)"unsubscribe should call subscribe_cb()",
+ "unsubscribe");
+ /* Send a regular command after unsubscribing, then disconnect */
+ state->disconnect = 1;
+ redisAsyncCommand(ac,integer_cb,state,"LPUSH mylist foo");
+
+ } else if (strcmp(reply->element[0]->str,"unsubscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
+ reply->element[2]->str == NULL);
+ } else {
+ printf("Unexpected pubsub command: %s\n", reply->element[0]->str);
+ exit(1);
+ }
+}
+
+/* Expect a reply of type ARRAY */
+void array_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+ assert(reply != NULL && reply->type == REDIS_REPLY_ARRAY);
+ state->checkpoint++;
+ if (state->disconnect) async_disconnect(ac);
+}
+
+/* Expect a NULL reply */
+void null_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ (void) ac;
+ assert(r == NULL);
+ TestState *state = privdata;
+ state->checkpoint++;
+}
+
+static void test_pubsub_handling(struct config config) {
+ test("Subscribe, handle published message and unsubscribe: ");
+ /* Setup event dispatcher with a testcase timeout */
+ base = event_base_new();
+ struct event *timeout = evtimer_new(base, timeout_cb, NULL);
+ assert(timeout != NULL);
+
+ evtimer_assign(timeout,base,timeout_cb,NULL);
+ struct timeval timeout_tv = {.tv_sec = 10};
+ evtimer_add(timeout, &timeout_tv);
+
+ /* Connect */
+ redisOptions options = get_redis_tcp_options(config);
+ redisAsyncContext *ac = redisAsyncConnectWithOptions(&options);
+ assert(ac != NULL && ac->err == 0);
+ redisLibeventAttach(ac,base);
+
+ /* Start subscribe */
+ TestState state = {.options = &options};
+ redisAsyncCommand(ac,subscribe_cb,&state,"subscribe mychannel");
+
+ /* Make sure non-subscribe commands are handled */
+ redisAsyncCommand(ac,array_cb,&state,"PING");
+
+ /* Start event dispatching loop */
+ test_cond(event_base_dispatch(base) == 0);
+ event_free(timeout);
+ event_base_free(base);
+
+ /* Verify test checkpoints */
+ assert(state.checkpoint == 3);
+}
+
+/* Unexpected push message, will trigger a failure */
+void unexpected_push_cb(redisAsyncContext *ac, void *r) {
+ (void) ac; (void) r;
+ printf("Unexpected call to the PUSH callback!\n");
+ exit(1);
+}
+
+static void test_pubsub_handling_resp3(struct config config) {
+ test("Subscribe, handle published message and unsubscribe using RESP3: ");
+ /* Setup event dispatcher with a testcase timeout */
+ base = event_base_new();
+ struct event *timeout = evtimer_new(base, timeout_cb, NULL);
+ assert(timeout != NULL);
+
+ evtimer_assign(timeout,base,timeout_cb,NULL);
+ struct timeval timeout_tv = {.tv_sec = 10};
+ evtimer_add(timeout, &timeout_tv);
+
+ /* Connect */
+ redisOptions options = get_redis_tcp_options(config);
+ redisAsyncContext *ac = redisAsyncConnectWithOptions(&options);
+ assert(ac != NULL && ac->err == 0);
+ redisLibeventAttach(ac,base);
+
+ /* Not expecting any push messages in this test */
+ redisAsyncSetPushCallback(ac, unexpected_push_cb);
+
+ /* Switch protocol */
+ redisAsyncCommand(ac,NULL,NULL,"HELLO 3");
+
+ /* Start subscribe */
+ TestState state = {.options = &options, .resp3 = 1};
+ redisAsyncCommand(ac,subscribe_cb,&state,"subscribe mychannel");
+
+ /* Make sure non-subscribe commands are handled in RESP3 */
+ redisAsyncCommand(ac,integer_cb,&state,"LPUSH mylist foo");
+ redisAsyncCommand(ac,integer_cb,&state,"LPUSH mylist foo");
+ redisAsyncCommand(ac,integer_cb,&state,"LPUSH mylist foo");
+ /* Handle an array with 3 elements as a non-subscribe command */
+ redisAsyncCommand(ac,array_cb,&state,"LRANGE mylist 0 2");
+
+ /* Start event dispatching loop */
+ test_cond(event_base_dispatch(base) == 0);
+ event_free(timeout);
+ event_base_free(base);
+
+ /* Verify test checkpoints */
+ assert(state.checkpoint == 6);
+}
+
+/* Subscribe callback for test_command_timeout_during_pubsub:
+ * - a subscribe response triggers a published message
+ * - the published message triggers a command that times out
+ * - the command timeout triggers a disconnect */
+void subscribe_with_timeout_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+
+ /* The non-clean disconnect should trigger the
+ * subscription callback with a NULL reply. */
+ if (reply == NULL) {
+ state->checkpoint++;
+ event_base_loopbreak(base);
+ return;
+ }
+
+ assert(reply->type == (state->resp3 ? REDIS_REPLY_PUSH : REDIS_REPLY_ARRAY) &&
+ reply->elements == 3);
+
+ if (strcmp(reply->element[0]->str,"subscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
+ reply->element[2]->str == NULL);
+ publish_msg(state->options,"mychannel","Hello!");
+ state->checkpoint++;
+ } else if (strcmp(reply->element[0]->str,"message") == 0) {
+ assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
+ strcmp(reply->element[2]->str,"Hello!") == 0);
+ state->checkpoint++;
+
+ /* Send a command that will trigger a timeout */
+ redisAsyncCommand(ac,null_cb,state,"DEBUG SLEEP 3");
+ redisAsyncCommand(ac,null_cb,state,"LPUSH mylist foo");
+ } else {
+ printf("Unexpected pubsub command: %s\n", reply->element[0]->str);
+ exit(1);
+ }
+}
+
+static void test_command_timeout_during_pubsub(struct config config) {
+ test("Command timeout during Pub/Sub: ");
+ /* Setup event dispatcher with a testcase timeout */
+ base = event_base_new();
+ struct event *timeout = evtimer_new(base,timeout_cb,NULL);
+ assert(timeout != NULL);
+
+ evtimer_assign(timeout,base,timeout_cb,NULL);
+ struct timeval timeout_tv = {.tv_sec = 10};
+ evtimer_add(timeout,&timeout_tv);
+
+ /* Connect */
+ redisOptions options = get_redis_tcp_options(config);
+ redisAsyncContext *ac = redisAsyncConnectWithOptions(&options);
+ assert(ac != NULL && ac->err == 0);
+ redisLibeventAttach(ac,base);
+
+ /* Configure a command timout */
+ struct timeval command_timeout = {.tv_sec = 2};
+ redisAsyncSetTimeout(ac,command_timeout);
+
+ /* Not expecting any push messages in this test */
+ redisAsyncSetPushCallback(ac,unexpected_push_cb);
+
+ /* Switch protocol */
+ redisAsyncCommand(ac,NULL,NULL,"HELLO 3");
+
+ /* Start subscribe */
+ TestState state = {.options = &options, .resp3 = 1};
+ redisAsyncCommand(ac,subscribe_with_timeout_cb,&state,"subscribe mychannel");
+
+ /* Start event dispatching loop */
+ assert(event_base_dispatch(base) == 0);
+ event_free(timeout);
+ event_base_free(base);
+
+ /* Verify test checkpoints */
+ test_cond(state.checkpoint == 5);
+}
+
+/* Subscribe callback for test_pubsub_multiple_channels */
+void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+
+ assert(reply != NULL && reply->type == REDIS_REPLY_ARRAY &&
+ reply->elements == 3);
+
+ if (strcmp(reply->element[0]->str,"subscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"A") == 0);
+ publish_msg(state->options,"A","Hello!");
+ state->checkpoint++;
+ } else if (strcmp(reply->element[0]->str,"message") == 0) {
+ assert(strcmp(reply->element[1]->str,"A") == 0 &&
+ strcmp(reply->element[2]->str,"Hello!") == 0);
+ state->checkpoint++;
+
+ /* Unsubscribe to channels, including a channel X which we don't subscribe to */
+ redisAsyncCommand(ac,unexpected_cb,
+ (void*)"unsubscribe should not call unexpected_cb()",
+ "unsubscribe B X A");
+ /* Send a regular command after unsubscribing, then disconnect */
+ state->disconnect = 1;
+ redisAsyncCommand(ac,integer_cb,state,"LPUSH mylist foo");
+ } else if (strcmp(reply->element[0]->str,"unsubscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"A") == 0);
+ state->checkpoint++;
+ } else {
+ printf("Unexpected pubsub command: %s\n", reply->element[0]->str);
+ exit(1);
+ }
+}
+
+/* Subscribe callback for test_pubsub_multiple_channels */
+void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+
+ assert(reply != NULL && reply->type == REDIS_REPLY_ARRAY &&
+ reply->elements == 3);
+
+ if (strcmp(reply->element[0]->str,"subscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"B") == 0);
+ state->checkpoint++;
+ } else if (strcmp(reply->element[0]->str,"unsubscribe") == 0) {
+ assert(strcmp(reply->element[1]->str,"B") == 0);
+ state->checkpoint++;
+ } else {
+ printf("Unexpected pubsub command: %s\n", reply->element[0]->str);
+ exit(1);
+ }
+}
+
+/* Test handling of multiple channels
+ * - subscribe to channel A and B
+ * - a published message on A triggers an unsubscribe of channel B, X and A
+ * where channel X is not subscribed to.
+ * - a command sent after unsubscribe triggers a disconnect */
+static void test_pubsub_multiple_channels(struct config config) {
+ test("Subscribe to multiple channels: ");
+ /* Setup event dispatcher with a testcase timeout */
+ base = event_base_new();
+ struct event *timeout = evtimer_new(base,timeout_cb,NULL);
+ assert(timeout != NULL);
+
+ evtimer_assign(timeout,base,timeout_cb,NULL);
+ struct timeval timeout_tv = {.tv_sec = 10};
+ evtimer_add(timeout,&timeout_tv);
+
+ /* Connect */
+ redisOptions options = get_redis_tcp_options(config);
+ redisAsyncContext *ac = redisAsyncConnectWithOptions(&options);
+ assert(ac != NULL && ac->err == 0);
+ redisLibeventAttach(ac,base);
+
+ /* Not expecting any push messages in this test */
+ redisAsyncSetPushCallback(ac,unexpected_push_cb);
+
+ /* Start subscribing to two channels */
+ TestState state = {.options = &options};
+ redisAsyncCommand(ac,subscribe_channel_a_cb,&state,"subscribe A");
+ redisAsyncCommand(ac,subscribe_channel_b_cb,&state,"subscribe B");
+
+ /* Start event dispatching loop */
+ assert(event_base_dispatch(base) == 0);
+ event_free(timeout);
+ event_base_free(base);
+
+ /* Verify test checkpoints */
+ test_cond(state.checkpoint == 6);
+}
+
+/* Command callback for test_monitor() */
+void monitor_cb(redisAsyncContext *ac, void *r, void *privdata) {
+ redisReply *reply = r;
+ TestState *state = privdata;
+
+ /* NULL reply is received when BYE triggers a disconnect. */
+ if (reply == NULL) {
+ event_base_loopbreak(base);
+ return;
+ }
+
+ assert(reply != NULL && reply->type == REDIS_REPLY_STATUS);
+ state->checkpoint++;
+
+ if (state->checkpoint == 1) {
+ /* Response from MONITOR */
+ redisContext *c = redisConnectWithOptions(state->options);
+ assert(c != NULL);
+ redisReply *reply = redisCommand(c,"SET first 1");
+ assert(reply->type == REDIS_REPLY_STATUS);
+ freeReplyObject(reply);
+ redisFree(c);
+ } else if (state->checkpoint == 2) {
+ /* Response for monitored command 'SET first 1' */
+ assert(strstr(reply->str,"first") != NULL);
+ redisContext *c = redisConnectWithOptions(state->options);
+ assert(c != NULL);
+ redisReply *reply = redisCommand(c,"SET second 2");
+ assert(reply->type == REDIS_REPLY_STATUS);
+ freeReplyObject(reply);
+ redisFree(c);
+ } else if (state->checkpoint == 3) {
+ /* Response for monitored command 'SET second 2' */
+ assert(strstr(reply->str,"second") != NULL);
+ /* Send QUIT to disconnect */
+ redisAsyncCommand(ac,NULL,NULL,"QUIT");
+ }
+}
+
+/* Test handling of the monitor command
+ * - sends MONITOR to enable monitoring.
+ * - sends SET commands via separate clients to be monitored.
+ * - sends QUIT to stop monitoring and disconnect. */
+static void test_monitor(struct config config) {
+ test("Enable monitoring: ");
+ /* Setup event dispatcher with a testcase timeout */
+ base = event_base_new();
+ struct event *timeout = evtimer_new(base, timeout_cb, NULL);
+ assert(timeout != NULL);
+
+ evtimer_assign(timeout,base,timeout_cb,NULL);
+ struct timeval timeout_tv = {.tv_sec = 10};
+ evtimer_add(timeout, &timeout_tv);
+
+ /* Connect */
+ redisOptions options = get_redis_tcp_options(config);
+ redisAsyncContext *ac = redisAsyncConnectWithOptions(&options);
+ assert(ac != NULL && ac->err == 0);
+ redisLibeventAttach(ac,base);
+
+ /* Not expecting any push messages in this test */
+ redisAsyncSetPushCallback(ac,unexpected_push_cb);
+
+ /* Start monitor */
+ TestState state = {.options = &options};
+ redisAsyncCommand(ac,monitor_cb,&state,"monitor");
+
+ /* Start event dispatching loop */
+ test_cond(event_base_dispatch(base) == 0);
+ event_free(timeout);
+ event_base_free(base);
+
+ /* Verify test checkpoints */
+ assert(state.checkpoint == 3);
+}
+#endif /* HIREDIS_TEST_ASYNC */
+
int main(int argc, char **argv) {
struct config cfg = {
.tcp = {
@@ -1401,6 +1999,24 @@ int main(int argc, char **argv) {
}
#endif
+#ifdef HIREDIS_TEST_ASYNC
+ printf("\nTesting asynchronous API against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port);
+ cfg.type = CONN_TCP;
+
+ int major;
+ redisContext *c = do_connect(cfg);
+ get_redis_version(c, &major, NULL);
+ disconnect(c, 0);
+
+ test_pubsub_handling(cfg);
+ test_pubsub_multiple_channels(cfg);
+ test_monitor(cfg);
+ if (major >= 6) {
+ test_pubsub_handling_resp3(cfg);
+ test_command_timeout_during_pubsub(cfg);
+ }
+#endif /* HIREDIS_TEST_ASYNC */
+
if (test_inherit_fd) {
printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path);
if (test_unix_socket) {