summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml20
-rw-r--r--CHANGELOG.md174
-rw-r--r--CMakeLists.txt19
-rw-r--r--README.md76
-rw-r--r--adapters/libev.h6
-rw-r--r--async.c17
-rw-r--r--async_private.h21
-rw-r--r--examples/example-libevent.c2
-rw-r--r--examples/example-push.c22
-rw-r--r--examples/example-ssl.c7
-rw-r--r--examples/example.c5
-rw-r--r--hiredis.c79
-rw-r--r--hiredis.h38
-rw-r--r--net.c42
-rw-r--r--ssl.c22
-rw-r--r--test.c27
16 files changed, 457 insertions, 120 deletions
diff --git a/.travis.yml b/.travis.yml
index d0a551a..1e9b556 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,6 +7,8 @@ os:
- linux
- osx
+dist: bionic
+
branches:
only:
- staging
@@ -14,6 +16,13 @@ branches:
- master
- /^release\/.*$/
+install:
+ - 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;
+
before_script:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.6.2-10.13-HighSierra.pkg;
@@ -24,8 +33,6 @@ before_script:
addons:
apt:
- sources:
- - sourceline: 'ppa:chris-lea/redis-server'
packages:
- libc6-dbg
- libc6-dev
@@ -37,14 +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";
+ - 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";
@@ -79,7 +85,11 @@ script:
- mkdir build/ && cd build/
- cmake .. ${EXTRA_CMAKE_OPTS}
- make VERBOSE=1
- - SKIPS_AS_FAILS=1 ctest -V
+ - if [ "$BITS" == "64" ]; then
+ TEST_SSL=1 SKIPS_AS_FAILS=1 ctest -V;
+ else
+ SKIPS_AS_FAILS=1 ctest -V;
+ fi;
jobs:
include:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1d37e5..271f1fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,28 +1,175 @@
-### 1.0.0 (unreleased)
+## [1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) - (2020-08-03)
-**BREAKING CHANGES**:
+Announcing Hiredis v1.0.0, which adds support for RESP3, SSL connections, allocator injection, and better Windows support! :tada:
-* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
- protocol errors. This is consistent with the RESP specification. On 32-bit
- platforms, the upper bound is lowered to `SIZE_MAX`.
+_A big thanks to everyone who helped with this release. The following list includes everyone who contributed at least five lines, sorted by lines contributed._ :sparkling_heart:
-* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
+[Michael Grunder](https://github.com/michael-grunder), [Yossi Gottlieb](https://github.com/yossigo),
+[Mark Nunberg](https://github.com/mnunberg), [Marcus Geelnard](https://github.com/mbitsnbites),
+[Justin Brewer](https://github.com/justinbrewer), [Valentino Geron](https://github.com/valentinogeron),
+[Minun Dragonation](https://github.com/dragonation), [Omri Steiner](https://github.com/OmriSteiner),
+[Sangmoon Yi](https://github.com/jman-krafton), [Jinjiazh](https://github.com/jinjiazhang),
+[Odin Hultgren Van Der Horst](https://github.com/Miniwoffer), [Muhammad Zahalqa](https://github.com/tryfinally),
+[Nick Rivera](https://github.com/heronr), [Qi Yang](https://github.com/movebean),
+[kevin1018](https://github.com/kevin1018)
- User code should compare this to `size_t` values as well. If it was used to
- compare to other values, casting might be necessary or can be removed, if
- casting was applied before.
+[Full Changelog](https://github.com/redis/hiredis/compare/v0.14.1...v1.0.0)
-### 0.x.x (unreleased)
**BREAKING CHANGES**:
-* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
+* `redisOptions` now has two timeout fields. One for connecting, and one for commands. If you're presently using `options->timeout` you will need to change it to use `options->connect_timeout`. (See [example](https://github.com/redis/hiredis/commit/38b5ae543f5c99eb4ccabbe277770fc6bc81226f#diff-86ba39d37aa829c8c82624cce4f049fbL36))
-User code should compare this to `size_t` values as well.
-If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
+* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now protocol errors. This is consistent
+ with the RESP specification. On 32-bit platforms, the upper bound is lowered to `SIZE_MAX`.
* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.
+**New features:**
+- Support for RESP3
+ [\#697](https://github.com/redis/hiredis/pull/697),
+ [\#805](https://github.com/redis/hiredis/pull/805),
+ [\#819](https://github.com/redis/hiredis/pull/819),
+ [\#841](https://github.com/redis/hiredis/pull/841)
+ ([Yossi Gottlieb](https://github.com/yossigo), [Michael Grunder](https://github.com/michael-grunder))
+- Support for SSL connections
+ [\#645](https://github.com/redis/hiredis/pull/645),
+ [\#699](https://github.com/redis/hiredis/pull/699),
+ [\#702](https://github.com/redis/hiredis/pull/702),
+ [\#708](https://github.com/redis/hiredis/pull/708),
+ [\#711](https://github.com/redis/hiredis/pull/711),
+ [\#821](https://github.com/redis/hiredis/pull/821),
+ [more](https://github.com/redis/hiredis/pulls?q=is%3Apr+is%3Amerged+SSL)
+ ([Mark Nunberg](https://github.com/mnunberg), [Yossi Gottlieb](https://github.com/yossigo))
+- Run-time allocator injection
+ [\#800](https://github.com/redis/hiredis/pull/800)
+ ([Michael Grunder](https://github.com/michael-grunder))
+- Improved Windows support (including MinGW and Windows CI)
+ [\#652](https://github.com/redis/hiredis/pull/652),
+ [\#663](https://github.com/redis/hiredis/pull/663)
+ ([Marcus Geelnard](https://www.bitsnbites.eu/author/m/))
+- Adds support for distinct connect and command timeouts
+ [\#839](https://github.com/redis/hiredis/pull/839),
+ [\#829](https://github.com/redis/hiredis/pull/829)
+ ([Valentino Geron](https://github.com/valentinogeron))
+- Add generic pointer and destructor to `redisContext` that users can use for context.
+ [\#855](https://github.com/redis/hiredis/pull/855)
+ ([Michael Grunder](https://github.com/michael-grunder))
+
+**Closed issues (that involved code changes):**
+
+- Makefile does not install TLS libraries [\#809](https://github.com/redis/hiredis/issues/809)
+- redisConnectWithOptions should not set command timeout [\#722](https://github.com/redis/hiredis/issues/722), [\#829](https://github.com/redis/hiredis/pull/829) ([valentinogeron](https://github.com/valentinogeron))
+- Fix integer overflow in `sdsrange` [\#827](https://github.com/redis/hiredis/issues/827)
+- INFO & CLUSTER commands failed when using RESP3 [\#802](https://github.com/redis/hiredis/issues/802)
+- Windows compatibility patches [\#687](https://github.com/redis/hiredis/issues/687), [\#838](https://github.com/redis/hiredis/issues/838), [\#842](https://github.com/redis/hiredis/issues/842)
+- RESP3 PUSH messages incorrectly use pending callback [\#825](https://github.com/redis/hiredis/issues/825)
+- Asynchronous PSUBSCRIBE command fails when using RESP3 [\#815](https://github.com/redis/hiredis/issues/815)
+- New SSL API [\#804](https://github.com/redis/hiredis/issues/804), [\#813](https://github.com/redis/hiredis/issues/813)
+- Hard-coded limit of nested reply depth [\#794](https://github.com/redis/hiredis/issues/794)
+- Fix TCP_NODELAY in Windows/OSX [\#679](https://github.com/redis/hiredis/issues/679), [\#690](https://github.com/redis/hiredis/issues/690), [\#779](https://github.com/redis/hiredis/issues/779), [\#785](https://github.com/redis/hiredis/issues/785),
+- Added timers to libev adapter. [\#778](https://github.com/redis/hiredis/issues/778), [\#795](https://github.com/redis/hiredis/pull/795)
+- Initialization discards const qualifier [\#777](https://github.com/redis/hiredis/issues/777)
+- \[BUG\]\[MinGW64\] Error setting socket timeout [\#775](https://github.com/redis/hiredis/issues/775)
+- undefined reference to hi_malloc [\#769](https://github.com/redis/hiredis/issues/769)
+- hiredis pkg-config file incorrectly ignores multiarch libdir spec'n [\#767](https://github.com/redis/hiredis/issues/767)
+- Don't use -G to build shared object on Solaris [\#757](https://github.com/redis/hiredis/issues/757)
+- error when make USE\_SSL=1 [\#748](https://github.com/redis/hiredis/issues/748)
+- Allow to change SSL Mode [\#646](https://github.com/redis/hiredis/issues/646)
+- hiredis/adapters/libevent.h memleak [\#618](https://github.com/redis/hiredis/issues/618)
+- redisLibuvPoll crash when server closes the connetion [\#545](https://github.com/redis/hiredis/issues/545)
+- about redisAsyncDisconnect question [\#518](https://github.com/redis/hiredis/issues/518)
+- hiredis adapters libuv error for help [\#508](https://github.com/redis/hiredis/issues/508)
+- API/ABI changes analysis [\#506](https://github.com/redis/hiredis/issues/506)
+- Memory leak patch in Redis [\#502](https://github.com/redis/hiredis/issues/502)
+- Remove the depth limitation [\#421](https://github.com/redis/hiredis/issues/421)
+
+**Merged pull requests:**
+
+- Move SSL management to a distinct private pointer [\#855](https://github.com/redis/hiredis/pull/855) ([michael-grunder](https://github.com/michael-grunder))
+- Move include to sockcompat.h to maintain style [\#850](https://github.com/redis/hiredis/pull/850) ([michael-grunder](https://github.com/michael-grunder))
+- Remove erroneous tag and add license to push example [\#849](https://github.com/redis/hiredis/pull/849) ([michael-grunder](https://github.com/michael-grunder))
+- fix windows compiling with mingw [\#848](https://github.com/redis/hiredis/pull/848) ([rmalizia44](https://github.com/rmalizia44))
+- Some Windows quality of life improvements. [\#846](https://github.com/redis/hiredis/pull/846) ([michael-grunder](https://github.com/michael-grunder))
+- Use \_WIN32 define instead of WIN32 [\#845](https://github.com/redis/hiredis/pull/845) ([michael-grunder](https://github.com/michael-grunder))
+- Non Linux CI fixes [\#844](https://github.com/redis/hiredis/pull/844) ([michael-grunder](https://github.com/michael-grunder))
+- Resp3 oob push support [\#841](https://github.com/redis/hiredis/pull/841) ([michael-grunder](https://github.com/michael-grunder))
+- fix \#785: defer TCP\_NODELAY in async tcp connections [\#836](https://github.com/redis/hiredis/pull/836) ([OmriSteiner](https://github.com/OmriSteiner))
+- sdsrange overflow fix [\#830](https://github.com/redis/hiredis/pull/830) ([michael-grunder](https://github.com/michael-grunder))
+- Use explicit pointer casting for c++ compatibility [\#826](https://github.com/redis/hiredis/pull/826) ([aureus1](https://github.com/aureus1))
+- Document allocator injection and completeness fix in test.c [\#824](https://github.com/redis/hiredis/pull/824) ([michael-grunder](https://github.com/michael-grunder))
+- Use unique names for allocator struct members [\#823](https://github.com/redis/hiredis/pull/823) ([michael-grunder](https://github.com/michael-grunder))
+- New SSL API to replace redisSecureConnection\(\). [\#821](https://github.com/redis/hiredis/pull/821) ([yossigo](https://github.com/yossigo))
+- Add logic to handle RESP3 push messages [\#819](https://github.com/redis/hiredis/pull/819) ([michael-grunder](https://github.com/michael-grunder))
+- Use standrad isxdigit instead of custom helper function. [\#814](https://github.com/redis/hiredis/pull/814) ([tryfinally](https://github.com/tryfinally))
+- Fix missing SSL build/install options. [\#812](https://github.com/redis/hiredis/pull/812) ([yossigo](https://github.com/yossigo))
+- Add link to ABI tracker [\#808](https://github.com/redis/hiredis/pull/808) ([michael-grunder](https://github.com/michael-grunder))
+- Resp3 verbatim string support [\#805](https://github.com/redis/hiredis/pull/805) ([michael-grunder](https://github.com/michael-grunder))
+- Allow users to replace allocator and handle OOM everywhere. [\#800](https://github.com/redis/hiredis/pull/800) ([michael-grunder](https://github.com/michael-grunder))
+- Remove nested depth limitation. [\#797](https://github.com/redis/hiredis/pull/797) ([michael-grunder](https://github.com/michael-grunder))
+- Attempt to fix compilation on Solaris [\#796](https://github.com/redis/hiredis/pull/796) ([michael-grunder](https://github.com/michael-grunder))
+- Support timeouts in libev adapater [\#795](https://github.com/redis/hiredis/pull/795) ([michael-grunder](https://github.com/michael-grunder))
+- Fix pkgconfig when installing to a custom lib dir [\#793](https://github.com/redis/hiredis/pull/793) ([michael-grunder](https://github.com/michael-grunder))
+- Fix USE\_SSL=1 make/cmake on OSX and CMake tests [\#789](https://github.com/redis/hiredis/pull/789) ([michael-grunder](https://github.com/michael-grunder))
+- Use correct libuv call on Windows [\#784](https://github.com/redis/hiredis/pull/784) ([michael-grunder](https://github.com/michael-grunder))
+- Added CMake package config and fixed hiredis\_ssl on Windows [\#783](https://github.com/redis/hiredis/pull/783) ([michael-grunder](https://github.com/michael-grunder))
+- CMake: Set hiredis\_ssl shared object version. [\#780](https://github.com/redis/hiredis/pull/780) ([yossigo](https://github.com/yossigo))
+- Win32 tests and timeout fix [\#776](https://github.com/redis/hiredis/pull/776) ([michael-grunder](https://github.com/michael-grunder))
+- Provides an optional cleanup callback for async data. [\#768](https://github.com/redis/hiredis/pull/768) ([heronr](https://github.com/heronr))
+- Housekeeping fixes [\#764](https://github.com/redis/hiredis/pull/764) ([michael-grunder](https://github.com/michael-grunder))
+- install alloc.h [\#756](https://github.com/redis/hiredis/pull/756) ([ch1aki](https://github.com/ch1aki))
+- fix spelling mistakes [\#746](https://github.com/redis/hiredis/pull/746) ([ShooterIT](https://github.com/ShooterIT))
+- Free the reply in redisGetReply when passed NULL [\#741](https://github.com/redis/hiredis/pull/741) ([michael-grunder](https://github.com/michael-grunder))
+- Fix dead code in sslLogCallback relating to should\_log variable. [\#737](https://github.com/redis/hiredis/pull/737) ([natoscott](https://github.com/natoscott))
+- Fix typo in dict.c. [\#731](https://github.com/redis/hiredis/pull/731) ([Kevin-Xi](https://github.com/Kevin-Xi))
+- Adding an option to DISABLE\_TESTS [\#727](https://github.com/redis/hiredis/pull/727) ([pbotros](https://github.com/pbotros))
+- Update README with SSL support. [\#720](https://github.com/redis/hiredis/pull/720) ([yossigo](https://github.com/yossigo))
+- Fixes leaks in unit tests [\#715](https://github.com/redis/hiredis/pull/715) ([michael-grunder](https://github.com/michael-grunder))
+- SSL Tests [\#711](https://github.com/redis/hiredis/pull/711) ([yossigo](https://github.com/yossigo))
+- SSL Reorganization [\#708](https://github.com/redis/hiredis/pull/708) ([yossigo](https://github.com/yossigo))
+- Fix MSVC build. [\#706](https://github.com/redis/hiredis/pull/706) ([yossigo](https://github.com/yossigo))
+- SSL: Properly report SSL\_connect\(\) errors. [\#702](https://github.com/redis/hiredis/pull/702) ([yossigo](https://github.com/yossigo))
+- Silent SSL trace to stdout by default. [\#699](https://github.com/redis/hiredis/pull/699) ([yossigo](https://github.com/yossigo))
+- Port RESP3 support from Redis. [\#697](https://github.com/redis/hiredis/pull/697) ([yossigo](https://github.com/yossigo))
+- Removed whitespace before newline [\#691](https://github.com/redis/hiredis/pull/691) ([Miniwoffer](https://github.com/Miniwoffer))
+- Add install adapters header files [\#688](https://github.com/redis/hiredis/pull/688) ([kevin1018](https://github.com/kevin1018))
+- Remove unnecessary null check before free [\#684](https://github.com/redis/hiredis/pull/684) ([qlyoung](https://github.com/qlyoung))
+- redisReaderGetReply leak memory [\#671](https://github.com/redis/hiredis/pull/671) ([movebean](https://github.com/movebean))
+- fix timeout code in windows [\#670](https://github.com/redis/hiredis/pull/670) ([jman-krafton](https://github.com/jman-krafton))
+- test: fix errstr matching for musl libc [\#665](https://github.com/redis/hiredis/pull/665) ([ghost](https://github.com/ghost))
+- Windows: MinGW fixes and Windows Travis builders [\#663](https://github.com/redis/hiredis/pull/663) ([mbitsnbites](https://github.com/mbitsnbites))
+- The setsockopt and getsockopt API diffs from BSD socket and WSA one [\#662](https://github.com/redis/hiredis/pull/662) ([dragonation](https://github.com/dragonation))
+- Fix Compile Error On Windows \(Visual Studio\) [\#658](https://github.com/redis/hiredis/pull/658) ([jinjiazhang](https://github.com/jinjiazhang))
+- Fix NXDOMAIN test case [\#653](https://github.com/redis/hiredis/pull/653) ([michael-grunder](https://github.com/michael-grunder))
+- Add MinGW support [\#652](https://github.com/redis/hiredis/pull/652) ([mbitsnbites](https://github.com/mbitsnbites))
+- SSL Support [\#645](https://github.com/redis/hiredis/pull/645) ([mnunberg](https://github.com/mnunberg))
+- Fix Invalid argument after redisAsyncConnectUnix [\#644](https://github.com/redis/hiredis/pull/644) ([codehz](https://github.com/codehz))
+- Makefile: use predefined AR [\#632](https://github.com/redis/hiredis/pull/632) ([Mic92](https://github.com/Mic92))
+- FreeBSD build fix [\#628](https://github.com/redis/hiredis/pull/628) ([devnexen](https://github.com/devnexen))
+- Fix errors not propagating properly with libuv.h. [\#624](https://github.com/redis/hiredis/pull/624) ([yossigo](https://github.com/yossigo))
+- Update README.md [\#621](https://github.com/redis/hiredis/pull/621) ([Crunsher](https://github.com/Crunsher))
+- Fix redisBufferRead documentation [\#620](https://github.com/redis/hiredis/pull/620) ([hacst](https://github.com/hacst))
+- Add CPPFLAGS to REAL\_CFLAGS [\#614](https://github.com/redis/hiredis/pull/614) ([thomaslee](https://github.com/thomaslee))
+- Update createArray to take size\_t [\#597](https://github.com/redis/hiredis/pull/597) ([justinbrewer](https://github.com/justinbrewer))
+- fix common realloc mistake and add null check more [\#580](https://github.com/redis/hiredis/pull/580) ([charsyam](https://github.com/charsyam))
+- Proper error reporting for connect failures [\#578](https://github.com/redis/hiredis/pull/578) ([mnunberg](https://github.com/mnunberg))
+
+\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
+
+## [1.0.0-rc1](https://github.com/redis/hiredis/tree/v1.0.0-rc1) - (2020-07-29)
+
+_Note: There were no changes to code between v1.0.0-rc1 and v1.0.0 so see v1.0.0 for changelog_
+
+### 0.14.1 (2020-03-13)
+
+* Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder)
+
### 0.14.0 (2018-09-25)
+**BREAKING CHANGES**:
+
+* Change `redisReply.len` to `size_t`, as it denotes the the size of a string
+
+ User code should compare this to `size_t` values as well.
+ If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.
* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])
* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
@@ -196,4 +343,3 @@ The parser, standalone since v0.12.0, can now be compiled on Windows
### 0.10.0
* See commit log.
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 55c026b..4bdee18 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,7 @@ PROJECT(hiredis)
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF)
+OPTION(ENABLE_SSL_TESTS, "Should we test SSL connections" OFF)
MACRO(getVersionBit name)
SET(VERSION_REGEX "^#define ${name} (.+)$")
@@ -21,6 +22,9 @@ MESSAGE("Detected version: ${VERSION}")
PROJECT(hiredis VERSION "${VERSION}")
+# Hiredis requires C99
+SET(CMAKE_C_STANDARD 99)
+
SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples")
SET(hiredis_sources
@@ -92,10 +96,10 @@ INSTALL(FILES hiredis.targets
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)
@@ -126,7 +130,7 @@ 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})
@@ -159,7 +163,7 @@ IF(ENABLE_SSL)
INSTALL(FILES hiredis_ssl.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis)
-
+
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
@@ -184,7 +188,12 @@ 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)
+ ENDIF()
ADD_TEST(NAME hiredis-test
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
ENDIF()
diff --git a/README.md b/README.md
index 3a43d48..3a22553 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)
-**This Readme reflects the latest changed in the master branch. See [v0.14.1](https://github.com/redis/hiredis/tree/v0.14.1) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).**
+**This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).**
# HIREDIS
@@ -24,12 +24,31 @@ The library comes with multiple APIs. There is the
## Upgrading to `1.0.0`
-Version 1.0.0 marks a stable release of hiredis.
+Version 1.0.0 marks the first stable release of Hiredis.
It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.
It also bundles the updated `sds` library, to sync up with upstream and Redis.
-For most applications a recompile against the new hiredis should be enough.
For code changes see the [Changelog](CHANGELOG.md).
+_Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._
+
+## IMPORTANT: Breaking changes from `0.14.1` -> `1.0.0`
+
+* `redisContext` has two additional members (`free_privdata`, and `privctx`).
+* `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`.
+* `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter.
+
+## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x
+
+Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
+protocol errors. This is consistent with the RESP specification. On 32-bit
+platforms, the upper bound is lowered to `SIZE_MAX`.
+
+Change `redisReply.len` to `size_t`, as it denotes the the size of a string
+
+User code should compare this to `size_t` values as well. If it was used to
+compare to other values, casting might be necessary or can be removed, if
+casting was applied before.
+
## Upgrading from `<0.9.0`
Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
@@ -110,6 +129,8 @@ The standard replies that `redisCommand` are of the type `redisReply`. The
`type` field in the `redisReply` should be used to test what kind of reply
was received:
+### RESP2
+
* **`REDIS_REPLY_STATUS`**:
* The command replied with a status reply. The status string can be accessed using `reply->str`.
The length of this string can be accessed using `reply->len`.
@@ -134,16 +155,51 @@ was received:
and can be accessed via `reply->element[..index..]`.
Redis may reply with nested arrays but this is fully supported.
+### RESP3
+
+Hiredis also supports every new `RESP3` data type which are as follows. For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md)
+
+* **`REDIS_REPLY_DOUBLE`**:
+ * The command replied with a double-precision floating point number.
+ The value is stored as a string in the `str` member, and can be converted with `strtod` or similar.
+
+* **`REDIS_REPLY_BOOL`**:
+ * A boolean true/false reply.
+ The value is stored in the `integer` member and will be either `0` or `1`.
+
+* **`REDIS_REPLY_MAP`**:
+ * An array with the added invariant that there will always be an even number of elements.
+ The MAP is functionally equivelant to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.
+
+* **`REDIS_REPLY_SET`**:
+ * An array response where each entry is unique.
+ Like the MAP type, the data is identical to an array response except there are no duplicate values.
+
+* **`REDIS_REPLY_PUSH`**:
+ * An array that can be generated spontaneously by Redis.
+ This array response will always contain at least two subelements. The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself.
+
+* **`REDIS_REPLY_ATTR`**:
+ * An array structurally identical to a `MAP` but intended as meta-data about a reply.
+ _As of Redis 6.0.6 this reply type is not used in Redis_
+
+* **`REDIS_REPLY_BIGNUM`**:
+ * A string representing an arbitrarily large signed or unsigned integer value.
+ The number will be encoded as a string in the `str` member of `redisReply`.
+
+* **`REDIS_REPLY_VERB`**:
+ * A verbatim string, intended to be presented to the user without modification.
+ The string payload is stored in the `str` memeber, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown).
+
Replies should be freed using the `freeReplyObject()` function.
Note that this function will take care of freeing sub-reply objects
contained in arrays and nested arrays, so there is no need for the user to
free the sub replies (it is actually harmful and will corrupt the memory).
-**Important:** the current version of hiredis (0.10.0) frees replies when the
+**Important:** the current version of hiredis (1.0.0) frees replies when the
asynchronous API is used. This means you should not call `freeReplyObject` when
you use this API. The reply is cleaned up by hiredis _after_ the callback
-returns. This behavior will probably change in future releases, so make sure to
-keep an eye on the changelog when upgrading (see issue #39).
+returns. We may introduce a flag to make this configurable in future versions of the library.
### Cleaning up
@@ -595,6 +651,8 @@ hiredisResetAllocators();
## AUTHORS
-Hiredis was written by Salvatore Sanfilippo (antirez at gmail),
-Pieter Noordhuis (pcnoordhuis at gmail), and Michael Grunder
-(michael dot grunder at gmail) and is released under the BSD license.
+Salvatore Sanfilippo (antirez at gmail),\
+Pieter Noordhuis (pcnoordhuis at gmail)\
+Michael Grunder (michael dot grunder at gmail)
+
+_Hiredis is released under the BSD license._
diff --git a/adapters/libev.h b/adapters/libev.h
index e1e7bbd..6191543 100644
--- a/adapters/libev.h
+++ b/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);
@@ -154,7 +154,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/async.c b/async.c
index 1073d8d..18a4a09 100644
--- a/async.c
+++ b/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);
@@ -868,19 +873,19 @@ redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPus
}
int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
- if (!ac->c.timeout) {
- ac->c.timeout = hi_calloc(1, sizeof(tv));
- if (ac->c.timeout == NULL) {
+ if (!ac->c.command_timeout) {
+ ac->c.command_timeout = hi_calloc(1, sizeof(tv));
+ if (ac->c.command_timeout == NULL) {
__redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory");
__redisAsyncCopyError(ac);
return REDIS_ERR;
}
}
- if (tv.tv_sec != ac->c.timeout->tv_sec ||
- tv.tv_usec != ac->c.timeout->tv_usec)
+ if (tv.tv_sec != ac->c.command_timeout->tv_sec ||
+ tv.tv_usec != ac->c.command_timeout->tv_usec)
{
- *ac->c.timeout = tv;
+ *ac->c.command_timeout = tv;
}
return REDIS_OK;
diff --git a/async_private.h b/async_private.h
index d0133ae..b9d23ff 100644
--- a/async_private.h
+++ b/async_private.h
@@ -54,15 +54,18 @@
} while(0);
static inline void refreshTimeout(redisAsyncContext *ctx) {
- if (ctx->c.timeout && ctx->ev.scheduleTimer &&
- (ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) {
- ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout);
- // } else {
- // printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout);
- // if (ctx->c.timeout){
- // printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec,
- // ctx->c.timeout->tv_usec);
- // }
+ #define REDIS_TIMER_ISSET(tvp) \
+ (tvp && ((tvp)->tv_sec || (tvp)->tv_usec))
+
+ #define REDIS_EL_TIMER(ac, tvp) \
+ if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \
+ (ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \
+ }
+
+ if (ctx->c.flags & REDIS_CONNECTED) {
+ REDIS_EL_TIMER(ctx, ctx->c.command_timeout);
+ } else {
+ REDIS_EL_TIMER(ctx, ctx->c.connect_timeout);
}
}
diff --git a/examples/example-libevent.c b/examples/example-libevent.c
index f3fa2a6..49bddd0 100644
--- a/examples/example-libevent.c
+++ b/examples/example-libevent.c
@@ -47,7 +47,7 @@ int main (int argc, char **argv) {
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
struct timeval tv = {0};
tv.tv_sec = 1;
- options.timeout = &tv;
+ options.connect_timeout = &tv;
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
diff --git a/examples/example-push.c b/examples/example-push.c
index 23dbd17..6bc1205 100644
--- a/examples/example-push.c
+++ b/examples/example-push.c
@@ -31,7 +31,6 @@
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
-#include <win32.h>
#define KEY_COUNT 5
@@ -97,6 +96,13 @@ void pushReplyHandler(void *privdata, void *r) {
freeReplyObject(reply);
}
+/* We aren't actually freeing anything here, but it is included to show that we can
+ * have hiredis call our data destructor when freeing the context */
+void privdata_dtor(void *privdata) {
+ unsigned int *icount = privdata;
+ printf("privdata_dtor(): In context privdata dtor (invalidations: %u)\n", *icount);
+}
+
int main(int argc, char **argv) {
unsigned int j, invalidations = 0;
redisContext *c;
@@ -108,6 +114,16 @@ int main(int argc, char **argv) {
redisOptions o = {0};
REDIS_OPTIONS_SET_TCP(&o, hostname, port);
+ /* Set our context privdata to the address of our invalidation counter. Each
+ * time our PUSH handler is called, hiredis will pass the privdata for context.
+ *
+ * This could also be done after we create the context like so:
+ *
+ * c->privdata = &invalidations;
+ * c->free_privdata = privdata_dtor;
+ */
+ REDIS_OPTIONS_SET_PRIVDATA(&o, &invalidations, privdata_dtor);
+
/* Set our custom PUSH message handler */
o.push_cb = pushReplyHandler;
@@ -118,10 +134,6 @@ int main(int argc, char **argv) {
/* Enable RESP3 and turn on client tracking */
enableClientTracking(c);
- /* Set our context privdata to the address of our invalidation counter. Each
- * time our PUSH handler is called, hiredis will pass the privdata for context */
- c->privdata = &invalidations;
-
/* Set some keys and then read them back. Once we do that, Redis will deliver
* invalidation push messages whenever the key is modified */
for (j = 0; j < KEY_COUNT; j++) {
diff --git a/examples/example-ssl.c b/examples/example-ssl.c
index 5eb2bbb..b8ca442 100644
--- a/examples/example-ssl.c
+++ b/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;
@@ -33,7 +36,7 @@ int main(int argc, char **argv) {
struct timeval tv = { 1, 500000 }; // 1.5 seconds
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
- options.timeout = &tv;
+ options.connect_timeout = &tv;
c = redisConnectWithOptions(&options);
if (c == NULL || c->err) {
diff --git a/examples/example.c b/examples/example.c
index 15dacbd..f1b8b4a 100644
--- a/examples/example.c
+++ b/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/hiredis.c b/hiredis.c
index e9761ec..a7fbf48 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -44,8 +44,11 @@
#include "async.h"
#include "win32.h"
+extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout);
+extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout);
+
static redisContextFuncs redisContextDefaultFuncs = {
- .free_privdata = NULL,
+ .free_privctx = NULL,
.async_read = redisAsyncRead,
.async_write = redisAsyncWrite,
.read = redisNetRead,
@@ -685,7 +688,7 @@ static void redisPushAutoFree(void *privdata, void *reply) {
freeReplyObject(reply);
}
-static redisContext *redisContextInit(const redisOptions *options) {
+static redisContext *redisContextInit(void) {
redisContext *c;
c = hi_calloc(1, sizeof(*c));
@@ -694,13 +697,6 @@ static redisContext *redisContextInit(const redisOptions *options) {
c->funcs = &redisContextDefaultFuncs;
- /* Set any user supplied RESP3 PUSH handler or use freeReplyObject
- * as a default unless specifically flagged that we don't want one. */
- if (options->push_cb != NULL)
- redisSetPushCallback(c, options->push_cb);
- else if (!(options->options & REDIS_OPT_NO_PUSH_AUTOFREE))
- redisSetPushCallback(c, redisPushAutoFree);
-
c->obuf = sdsempty();
c->reader = redisReaderCreate();
c->fd = REDIS_INVALID_FD;
@@ -709,7 +705,7 @@ static redisContext *redisContextInit(const redisOptions *options) {
redisFree(c);
return NULL;
}
- (void)options; /* options are used in other functions */
+
return c;
}
@@ -723,11 +719,16 @@ void redisFree(redisContext *c) {
hi_free(c->tcp.host);
hi_free(c->tcp.source_addr);
hi_free(c->unix_sock.path);
- hi_free(c->timeout);
+ hi_free(c->connect_timeout);
+ hi_free(c->command_timeout);
hi_free(c->saddr);
- if (c->funcs->free_privdata) {
- c->funcs->free_privdata(c->privdata);
- }
+
+ if (c->privdata && c->free_privdata)
+ c->free_privdata(c->privdata);
+
+ if (c->funcs->free_privctx)
+ c->funcs->free_privctx(c->privctx);
+
memset(c, 0xff, sizeof(*c));
hi_free(c);
}
@@ -743,9 +744,9 @@ int redisReconnect(redisContext *c) {
c->err = 0;
memset(c->errstr, '\0', strlen(c->errstr));
- if (c->privdata && c->funcs->free_privdata) {
- c->funcs->free_privdata(c->privdata);
- c->privdata = NULL;
+ if (c->privctx && c->funcs->free_privctx) {
+ c->funcs->free_privctx(c->privctx);
+ c->privctx = NULL;
}
redisNetClose(c);
@@ -761,22 +762,28 @@ int redisReconnect(redisContext *c) {
return REDIS_ERR;
}
+ int ret = REDIS_ERR;
if (c->connection_type == REDIS_CONN_TCP) {
- return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
- c->timeout, c->tcp.source_addr);
+ ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
+ c->connect_timeout, c->tcp.source_addr);
} else if (c->connection_type == REDIS_CONN_UNIX) {
- return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
+ ret = redisContextConnectUnix(c, c->unix_sock.path, c->connect_timeout);
} else {
/* Something bad happened here and shouldn't have. There isn't
enough information in the context to reconnect. */
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
+ ret = REDIS_ERR;
}
- return REDIS_ERR;
+ if (c->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
+ redisContextSetTimeout(c, *c->command_timeout);
+ }
+
+ return ret;
}
redisContext *redisConnectWithOptions(const redisOptions *options) {
- redisContext *c = redisContextInit(options);
+ redisContext *c = redisContextInit();
if (c == NULL) {
return NULL;
}
@@ -790,13 +797,29 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
c->flags |= REDIS_NO_AUTO_FREE;
}
+ /* Set any user supplied RESP3 PUSH handler or use freeReplyObject
+ * as a default unless specifically flagged that we don't want one. */
+ if (options->push_cb != NULL)
+ redisSetPushCallback(c, options->push_cb);
+ else if (!(options->options & REDIS_OPT_NO_PUSH_AUTOFREE))
+ redisSetPushCallback(c, redisPushAutoFree);
+
+ c->privdata = options->privdata;
+ c->free_privdata = options->free_privdata;
+
+ if (redisContextUpdateConnectTimeout(c, options->connect_timeout) != REDIS_OK ||
+ redisContextUpdateCommandTimeout(c, options->command_timeout) != REDIS_OK) {
+ __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
+ return c;
+ }
+
if (options->type == REDIS_CONN_TCP) {
redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
- options->endpoint.tcp.port, options->timeout,
+ options->endpoint.tcp.port, options->connect_timeout,
options->endpoint.tcp.source_addr);
} else if (options->type == REDIS_CONN_UNIX) {
redisContextConnectUnix(c, options->endpoint.unix_socket,
- options->timeout);
+ options->connect_timeout);
} else if (options->type == REDIS_CONN_USERFD) {
c->fd = options->endpoint.fd;
c->flags |= REDIS_CONNECTED;
@@ -805,6 +828,10 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
return NULL;
}
+ if (options->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
+ redisContextSetTimeout(c, *options->command_timeout);
+ }
+
return c;
}
@@ -820,7 +847,7 @@ redisContext *redisConnect(const char *ip, int port) {
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
- options.timeout = &tv;
+ options.connect_timeout = &tv;
return redisConnectWithOptions(&options);
}
@@ -858,7 +885,7 @@ redisContext *redisConnectUnix(const char *path) {
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
- options.timeout = &tv;
+ options.connect_timeout = &tv;
return redisConnectWithOptions(&options);
}
diff --git a/hiredis.h b/hiredis.h
index 20e9bfa..a629930 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -45,10 +45,10 @@ typedef long long ssize_t;
#include "sds.h" /* for sds */
#include "alloc.h" /* for allocation wrappers */
-#define HIREDIS_MAJOR 0
-#define HIREDIS_MINOR 15
-#define HIREDIS_PATCH 0
-#define HIREDIS_SONAME 0.15
+#define HIREDIS_MAJOR 1
+#define HIREDIS_MINOR 0
+#define HIREDIS_PATCH 1
+#define HIREDIS_SONAME 1.0.1-dev
/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
@@ -176,8 +176,11 @@ typedef struct {
int type;
/* bit field of REDIS_OPT_xxx */
int options;
- /* timeout value. if NULL, no timeout is used */
- const struct timeval *timeout;
+ /* timeout value for connect operation. If NULL, no timeout is used */
+ const struct timeval *connect_timeout;
+ /* timeout value for commands. If NULL, no timeout is used. This can be
+ * updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */
+ const struct timeval *command_timeout;
union {
/** use this field for tcp/ip connections */
struct {
@@ -193,6 +196,10 @@ typedef struct {
redisFD fd;
} endpoint;
+ /* Optional user defined data/destructor */
+ void *privdata;
+ void (*free_privdata)(void *);
+
/* A user defined PUSH message callback */
redisPushFn *push_cb;
redisAsyncPushFn *async_push_cb;
@@ -210,8 +217,12 @@ typedef struct {
(opts)->type = REDIS_CONN_UNIX; \
(opts)->endpoint.unix_socket = path;
+#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \
+ (opts)->privdata = data; \
+ (opts)->free_privdata = dtor; \
+
typedef struct redisContextFuncs {
- void (*free_privdata)(void *);
+ void (*free_privctx)(void *);
void (*async_read)(struct redisAsyncContext *);
void (*async_write)(struct redisAsyncContext *);
ssize_t (*read)(struct redisContext *, char *, size_t);
@@ -230,7 +241,8 @@ typedef struct redisContext {
redisReader *reader; /* Protocol reader */
enum redisConnectionType connection_type;
- struct timeval *timeout;
+ struct timeval *connect_timeout;
+ struct timeval *command_timeout;
struct {
char *host;
@@ -243,11 +255,17 @@ typedef struct redisContext {
} unix_sock;
/* For non-blocking connect */
- struct sockadr *saddr;
+ struct sockaddr *saddr;
size_t addrlen;
- /* Additional private data for hiredis addons such as SSL */
+ /* Optional data and corresponding destructor users can use to provide
+ * context to a given redisContext. Not used by hiredis. */
void *privdata;
+ void (*free_privdata)(void *);
+
+ /* Internal context pointer presently used by hiredis to manage
+ * SSL connections. */
+ void *privctx;
/* An optional RESP3 PUSH handler */
redisPushFn *push_cb;
diff --git a/net.c b/net.c
index 882e2c4..c6b0e5d 100644
--- a/net.c
+++ b/net.c
@@ -217,7 +217,7 @@ int redisSetTcpNoDelay(redisContext *c) {
static int redisContextTimeoutMsec(redisContext *c, long *result)
{
- const struct timeval *timeout = c->timeout;
+ const struct timeval *timeout = c->connect_timeout;
long msec = -1;
/* Only use timeout when not NULL. */
@@ -328,19 +328,35 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
return REDIS_OK;
}
-static int _redisContextUpdateTimeout(redisContext *c, const struct timeval *timeout) {
+int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) {
/* Same timeval struct, short circuit */
- if (c->timeout == timeout)
+ if (c->connect_timeout == timeout)
return REDIS_OK;
/* Allocate context timeval if we need to */
- if (c->timeout == NULL) {
- c->timeout = hi_malloc(sizeof(*c->timeout));
- if (c->timeout == NULL)
+ if (c->connect_timeout == NULL) {
+ c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout));
+ if (c->connect_timeout == NULL)
return REDIS_ERR;
}
- memcpy(c->timeout, timeout, sizeof(*c->timeout));
+ memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout));
+ return REDIS_OK;
+}
+
+int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) {
+ /* Same timeval struct, short circuit */
+ if (c->command_timeout == timeout)
+ return REDIS_OK;
+
+ /* Allocate context timeval if we need to */
+ if (c->command_timeout == NULL) {
+ c->command_timeout = hi_malloc(sizeof(*c->command_timeout));
+ if (c->command_timeout == NULL)
+ return REDIS_ERR;
+ }
+
+ memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout));
return REDIS_OK;
}
@@ -376,11 +392,11 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
}
if (timeout) {
- if (_redisContextUpdateTimeout(c, timeout) == REDIS_ERR)
+ if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
goto oom;
} else {
- hi_free(c->timeout);
- c->timeout = NULL;
+ hi_free(c->connect_timeout);
+ c->connect_timeout = NULL;
}
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
@@ -549,11 +565,11 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
}
if (timeout) {
- if (_redisContextUpdateTimeout(c, timeout) == REDIS_ERR)
+ if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
goto oom;
} else {
- hi_free(c->timeout);
- c->timeout = NULL;
+ hi_free(c->connect_timeout);
+ c->connect_timeout = NULL;
}
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
diff --git a/ssl.c b/ssl.c
index d74212d..7df58fb 100644
--- a/ssl.c
+++ b/ssl.c
@@ -267,7 +267,7 @@ error:
static int redisSSLConnect(redisContext *c, SSL *ssl) {
- if (c->privdata) {
+ if (c->privctx) {
__redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated");
return REDIS_ERR;
}
@@ -288,14 +288,14 @@ static int redisSSLConnect(redisContext *c, SSL *ssl) {
ERR_clear_error();
int rv = SSL_connect(rssl->ssl);
if (rv == 1) {
- c->privdata = rssl;
+ c->privctx = rssl;
return REDIS_OK;
}
rv = SSL_get_error(rssl->ssl, rv);
if (((c->flags & REDIS_BLOCK) == 0) &&
(rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) {
- c->privdata = rssl;
+ c->privctx = rssl;
return REDIS_OK;
}
@@ -337,7 +337,7 @@ int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
/* We want to verify that redisSSLConnect() won't fail on this, as it will
* not own the SSL object in that case and we'll end up leaking.
*/
- if (c->privdata)
+ if (c->privctx)
return REDIS_ERR;
SSL *ssl = SSL_new(redis_ssl_ctx->ssl_ctx);
@@ -381,8 +381,8 @@ static int maybeCheckWant(redisSSL *rssl, int rv) {
* Implementation of redisContextFuncs for SSL connections.
*/
-static void redisSSLFree(void *privdata){
- redisSSL *rsc = privdata;
+static void redisSSLFree(void *privctx){
+ redisSSL *rsc = privctx;
if (!rsc) return;
if (rsc->ssl) {
@@ -393,7 +393,7 @@ static void redisSSLFree(void *privdata){
}
static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
- redisSSL *rssl = c->privdata;
+ redisSSL *rssl = c->privctx;
int nread = SSL_read(rssl->ssl, buf, bufcap);
if (nread > 0) {
@@ -435,7 +435,7 @@ static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
}
static ssize_t redisSSLWrite(redisContext *c) {
- redisSSL *rssl = c->privdata;
+ redisSSL *rssl = c->privctx;
size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
int rv = SSL_write(rssl->ssl, c->obuf, len);
@@ -458,7 +458,7 @@ static ssize_t redisSSLWrite(redisContext *c) {
static void redisSSLAsyncRead(redisAsyncContext *ac) {
int rv;
- redisSSL *rssl = ac->c.privdata;
+ redisSSL *rssl = ac->c.privctx;
redisContext *c = &ac->c;
rssl->wantRead = 0;
@@ -488,7 +488,7 @@ static void redisSSLAsyncRead(redisAsyncContext *ac) {
static void redisSSLAsyncWrite(redisAsyncContext *ac) {
int rv, done = 0;
- redisSSL *rssl = ac->c.privdata;
+ redisSSL *rssl = ac->c.privctx;
redisContext *c = &ac->c;
rssl->pendingWrite = 0;
@@ -517,7 +517,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
}
redisContextFuncs redisContextSSLFuncs = {
- .free_privdata = redisSSLFree,
+ .free_privctx = redisSSLFree,
.async_read = redisSSLAsyncRead,
.async_write = redisSSLAsyncWrite,
.read = redisSSLRead,
diff --git a/test.c b/test.c
index 2216ea3..c0eeca7 100644
--- a/test.c
+++ b/test.c
@@ -49,6 +49,10 @@ struct config {
} ssl;
};
+struct privdata {
+ int dtor_counter;
+};
+
#ifdef HIREDIS_TEST_SSL
redisSSLContext *_ssl_ctx = NULL;
#endif
@@ -786,6 +790,27 @@ static void test_resp3_push_options(struct config config) {
redisAsyncFree(ac);
}
+void free_privdata(void *privdata) {
+ struct privdata *data = privdata;
+ data->dtor_counter++;
+}
+
+static void test_privdata_hooks(struct config config) {
+ struct privdata data = {0};
+ redisOptions options;
+ redisContext *c;
+
+ test("We can use redisOptions to set privdata: ");
+ options = get_redis_tcp_options(config);
+ REDIS_OPTIONS_SET_PRIVDATA(&options, &data, free_privdata);
+ assert((c = redisConnectWithOptions(&options)) != NULL);
+ test_cond(c->privdata == &data);
+
+ test("Our privdata destructor fires when we free the context: ");
+ redisFree(c);
+ test_cond(data.dtor_counter == 1);
+}
+
static void test_blocking_connection(struct config config) {
redisContext *c;
redisReply *reply;
@@ -871,6 +896,8 @@ static void test_blocking_connection(struct config config) {
if (major >= 6) test_resp3_push_handler(c);
test_resp3_push_options(config);
+ test_privdata_hooks(config);
+
disconnect(c, 0);
}