Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package hiredis for openSUSE:Factory checked in at 2023-10-30 22:10:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/hiredis (Old) and /work/SRC/openSUSE:Factory/.hiredis.new.17445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hiredis" Mon Oct 30 22:10:33 2023 rev:13 rq:1121044 version:1.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/hiredis/hiredis.changes 2023-01-03 15:06:08.434781337 +0100 +++ /work/SRC/openSUSE:Factory/.hiredis.new.17445/hiredis.changes 2023-10-30 22:10:48.076251868 +0100 @@ -1,0 +2,10 @@ +Sat Oct 28 16:26:02 UTC 2023 - Andreas Stieger <[email protected]> + +- hiredis 1.2.0: + * Add sdevent adapter + * Allow specifying the keepalive interval + * Add RedisModule adapter + * Helper for setting TCP_USER_TIMEOUT socket option + * bug fixes + +------------------------------------------------------------------- Old: ---- v1.1.0.tar.gz New: ---- v1.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ hiredis.spec ++++++ --- /var/tmp/diff_new_pack.Q1yAzb/_old 2023-10-30 22:10:48.740276365 +0100 +++ /var/tmp/diff_new_pack.Q1yAzb/_new 2023-10-30 22:10:48.744276512 +0100 @@ -18,7 +18,7 @@ %global libname lib%{name}1_1_0 Name: hiredis -Version: 1.1.0 +Version: 1.2.0 Release: 0 Summary: Minimalistic C client for Redis License: BSD-3-Clause ++++++ v1.1.0.tar.gz -> v1.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/.github/workflows/build.yml new/hiredis-1.2.0/.github/workflows/build.yml --- old/hiredis-1.1.0/.github/workflows/build.yml 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/.github/workflows/build.yml 2023-07-12 09:31:17.000000000 +0200 @@ -133,8 +133,8 @@ - name: Install dependencies run: | - brew install openssl [email protected] - brew link [email protected] --force + brew install openssl [email protected] + brew link [email protected] --force - name: Build hiredis run: USE_SSL=1 make diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/.github/workflows/test.yml new/hiredis-1.2.0/.github/workflows/test.yml --- old/hiredis-1.1.0/.github/workflows/test.yml 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/.github/workflows/test.yml 2023-07-12 09:31:17.000000000 +0200 @@ -60,7 +60,7 @@ steps: - name: Install qemu if: matrix.emulator - run: sudo apt-get install -y qemu-user + run: sudo apt-get update && sudo apt-get install -y qemu-user - name: Install platform toolset if: matrix.toolset run: sudo apt-get install -y gcc-${{matrix.toolset}} @@ -82,12 +82,14 @@ steps: - uses: microsoft/[email protected] - uses: actions/checkout@v3 - - name: Run CMake - run: cmake -Wno-dev CmakeLists.txt - - name: Build hiredis + - name: Run CMake (shared lib) + run: cmake -Wno-dev CMakeLists.txt + - name: Build hiredis (shared lib) + run: MSBuild hiredis.vcxproj /p:Configuration=Debug + - name: Run CMake (static lib) + run: cmake -Wno-dev CMakeLists.txt -DBUILD_SHARED_LIBS=OFF + - name: Build hiredis (static lib) run: MSBuild hiredis.vcxproj /p:Configuration=Debug - - name: Build hiredis_static - run: MSBuild hiredis_static.vcxproj /p:Configuration=Debug - name: Build hiredis-test run: MSBuild hiredis-test.vcxproj /p:Configuration=Debug # use memurai, redis compatible server, since it is easy to install. Can't diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/CHANGELOG.md new/hiredis-1.2.0/CHANGELOG.md --- old/hiredis-1.1.0/CHANGELOG.md 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/CHANGELOG.md 2023-07-12 09:31:17.000000000 +0200 @@ -1,12 +1,63 @@ +## [1.2.0](https://github.com/redis/hiredis/tree/v1.2.0) - (2023-06-04) + +Announcing Hiredis v1.2.0 with with new adapters, and a great many bug fixes. + +## ð New Features + +- Add sdevent adapter @Oipo (#1144) +- Allow specifying the keepalive interval @michael-grunder (#1168) +- Add RedisModule adapter @tezc (#1182) +- Helper for setting TCP_USER_TIMEOUT socket option @zuiderkwast (#1188) + +## ð Bug Fixes + +- Fix a typo in b6a052f. @yossigo (#1190) +- Fix wincrypt symbols conflict @hudayou (#1151) +- Don't attempt to set a timeout if we are in an error state. @michael-grunder (#1180) +- Accept -nan per the RESP3 spec recommendation. @michael-grunder (#1178) +- Fix colliding option values @zuiderkwast (#1172) +- Ensure functionality without `_MSC_VER` definition @windyakin (#1194) + +## ð§° Maintenance + +- Add a test for the TCP_USER_TIMEOUT option. @michael-grunder (#1192) +- Add -Werror as a default. @yossigo (#1193) +- CI: Update homebrew Redis version. @yossigo (#1191) +- Fix typo in makefile. @michael-grunder (#1179) +- Write a version file for the CMake package @Neverlord (#1165) +- CMakeLists.txt: respect BUILD_SHARED_LIBS @ffontaine (#1147) +- Cmake static or shared @autoantwort (#1160) +- fix typo @tillkruss (#1153) +- Add a test ensuring we don't clobber connection error. @michael-grunder (#1181) +- Search for openssl on macOS @michael-grunder (#1169) + + +## Contributors +We'd like to thank all the contributors who worked on this release! + +<a href="https://github.com/neverlord"><img src="https://github.com/neverlord.png" width="32" height="32"></a> +<a href="https://github.com/Oipo"><img src="https://github.com/Oipo.png" width="32" height="32"></a> +<a href="https://github.com/autoantwort"><img src="https://github.com/autoantwort.png" width="32" height="32"></a> +<a href="https://github.com/ffontaine"><img src="https://github.com/ffontaine.png" width="32" height="32"></a> +<a href="https://github.com/hudayou"><img src="https://github.com/hudayou.png" width="32" height="32"></a> +<a href="https://github.com/michael-grunder"><img src="https://github.com/michael-grunder.png" width="32" height="32"></a> +<a href="https://github.com/postgraph"><img src="https://github.com/postgraph.png" width="32" height="32"></a> +<a href="https://github.com/tezc"><img src="https://github.com/tezc.png" width="32" height="32"></a> +<a href="https://github.com/tillkruss"><img src="https://github.com/tillkruss.png" width="32" height="32"></a> +<a href="https://github.com/vityafx"><img src="https://github.com/vityafx.png" width="32" height="32"></a> +<a href="https://github.com/windyakin"><img src="https://github.com/windyakin.png" width="32" height="32"></a> +<a href="https://github.com/yossigo"><img src="https://github.com/yossigo.png" width="32" height="32"></a> +<a href="https://github.com/zuiderkwast"><img src="https://github.com/zuiderkwast.png" width="32" height="32"></a> + ## [1.1.0](https://github.com/redis/hiredis/tree/v1.1.0) - (2022-11-15) Announcing Hiredis v1.1.0 GA with better SSL convenience, new async adapters and a great many bug fixes. -**NOTE**: Hiredis can now return `nan` in addition to `-inf` and `inf` when returning a `REDIS_REPLY_DOUBLE`. +**NOTE**: Hiredis can now return `nan` in addition to `-inf` and `inf` when returning a `REDIS_REPLY_DOUBLE`. ## ð Bug Fixes -- Add support for nan in RESP3 double [@filipecosta90](https://github.com/filipecosta90) +- Add support for nan in RESP3 double [@filipecosta90](https://github.com/filipecosta90) ([\#1133](https://github.com/redis/hiredis/pull/1133)) ## ð§° Maintenance @@ -14,7 +65,7 @@ - Add an example that calls redisCommandArgv [@michael-grunder](https://github.com/michael-grunder) ([\#1140](https://github.com/redis/hiredis/pull/1140)) - fix flag reference [@pata00](https://github.com/pata00) ([\#1136](https://github.com/redis/hiredis/pull/1136)) -- Make freeing a NULL redisAsyncContext a no op. [@michael-grunder](https://github.com/michael-grunder) +- Make freeing a NULL redisAsyncContext a no op. [@michael-grunder](https://github.com/michael-grunder) ([\#1135](https://github.com/redis/hiredis/pull/1135)) - CI updates ([@bjosv](https://github.com/redis/bjosv) ([\#1139](https://github.com/redis/hiredis/pull/1139)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/CMakeLists.txt new/hiredis-1.2.0/CMakeLists.txt --- old/hiredis-1.1.0/CMakeLists.txt 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/CMakeLists.txt 2023-07-12 09:31:17.000000000 +0200 @@ -1,8 +1,10 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0) +OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON) 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_EXAMPLES "Enable building hiredis examples" OFF) OPTION(ENABLE_ASYNC_TESTS "Should we run all asynchronous API tests" OFF) MACRO(getVersionBit name) @@ -24,11 +26,8 @@ # 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") - SET(hiredis_sources alloc.c async.c @@ -44,36 +43,27 @@ ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN) ENDIF() -ADD_LIBRARY(hiredis SHARED ${hiredis_sources}) -ADD_LIBRARY(hiredis_static STATIC ${hiredis_sources}) +ADD_LIBRARY(hiredis ${hiredis_sources}) ADD_LIBRARY(hiredis::hiredis ALIAS hiredis) -ADD_LIBRARY(hiredis::hiredis_static ALIAS hiredis_static) - -IF(NOT MSVC) - SET_TARGET_PROPERTIES(hiredis_static - PROPERTIES OUTPUT_NAME hiredis) -ENDIF() +set(hiredis_export_name hiredis CACHE STRING "Name of the exported target") +set_target_properties(hiredis PROPERTIES EXPORT_NAME ${hiredis_export_name}) SET_TARGET_PROPERTIES(hiredis PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE VERSION "${HIREDIS_SONAME}") IF(MSVC) - SET_TARGET_PROPERTIES(hiredis_static + SET_TARGET_PROPERTIES(hiredis PROPERTIES COMPILE_FLAGS /Z7) ENDIF() -IF(WIN32 OR MINGW) +IF(WIN32) 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: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) @@ -103,13 +93,13 @@ include(CPack) -INSTALL(TARGETS hiredis hiredis_static +INSTALL(TARGETS hiredis EXPORT hiredis-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -if (MSVC) +if (MSVC AND BUILD_SHARED_LIBS) INSTALL(FILES $<TARGET_PDB_FILE:hiredis> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo) @@ -139,6 +129,8 @@ endif() SET(INCLUDE_INSTALL_DIR include) include(CMakePackageConfigHelpers) +write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/hiredis-config-version.cmake" + COMPATIBILITY SameMajorVersion) configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR) @@ -149,6 +141,7 @@ DESTINATION ${CMAKE_CONF_INSTALL_DIR}) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config-version.cmake DESTINATION ${CMAKE_CONF_INSTALL_DIR}) @@ -161,16 +154,10 @@ FIND_PACKAGE(OpenSSL REQUIRED) SET(hiredis_ssl_sources ssl.c) - ADD_LIBRARY(hiredis_ssl SHARED - ${hiredis_ssl_sources}) - ADD_LIBRARY(hiredis_ssl_static STATIC - ${hiredis_ssl_sources}) - IF(NOT MSVC) - SET_TARGET_PROPERTIES(hiredis_ssl_static - PROPERTIES OUTPUT_NAME hiredis_ssl) - ENDIF() + ADD_LIBRARY(hiredis_ssl ${hiredis_ssl_sources}) + ADD_LIBRARY(hiredis::hiredis_ssl ALIAS hiredis_ssl) - IF (APPLE) + IF (APPLE AND BUILD_SHARED_LIBS) SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup") ENDIF() @@ -179,27 +166,22 @@ WINDOWS_EXPORT_ALL_SYMBOLS TRUE VERSION "${HIREDIS_SONAME}") IF(MSVC) - SET_TARGET_PROPERTIES(hiredis_ssl_static + SET_TARGET_PROPERTIES(hiredis_ssl PROPERTIES COMPILE_FLAGS /Z7) ENDIF() - - 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 OpenSSL::SSL) + IF(WIN32) 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 hiredis_ssl_static + INSTALL(TARGETS hiredis_ssl EXPORT hiredis_ssl-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - if (MSVC) + if (MSVC AND BUILD_SHARED_LIBS) INSTALL(FILES $<TARGET_PDB_FILE:hiredis_ssl> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo) @@ -251,5 +233,5 @@ # Add examples IF(ENABLE_EXAMPLES) - ADD_SUBDIRECTORY(examples) + ADD_SUBDIRECTORY(examples) ENDIF(ENABLE_EXAMPLES) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/Makefile new/hiredis-1.2.0/Makefile --- old/hiredis-1.1.0/Makefile 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/Makefile 2023-07-12 09:31:17.000000000 +0200 @@ -39,7 +39,7 @@ CC:=$(shell sh -c 'type $${CC%% *} >/dev/null 2>/dev/null && echo $(CC) || echo gcc') CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++') OPTIMIZATION?=-O3 -WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers +WARNINGS=-Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers DEBUG_FLAGS?= -g -ggdb REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) $(PLATFORM_FLAGS) REAL_LDFLAGS=$(LDFLAGS) @@ -92,18 +92,25 @@ endif 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 + ifndef OPENSSL_PREFIX + ifeq ($(uname_S),Darwin) + SEARCH_PATH1=/opt/homebrew/opt/openssl + SEARCH_PATH2=/usr/local/opt/openssl + + ifneq ($(wildcard $(SEARCH_PATH1)),) + OPENSSL_PREFIX=$(SEARCH_PATH1) + else ifneq ($(wildcard $(SEARCH_PATH2)),) + OPENSSL_PREFIX=$(SEARCH_PATH2) + endif endif - else - OPENSSL_PREFIX?=/usr/local/opt/openssl + endif + + ifdef OPENSSL_PREFIX CFLAGS+=-I$(OPENSSL_PREFIX)/include - SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto + SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib endif + + SSL_LDFLAGS+=-lssl -lcrypto endif ifeq ($(uname_S),FreeBSD) @@ -304,7 +311,7 @@ $(INSTALL) hiredis.h async.h read.h sds.h alloc.h sockcompat.h $(INSTALL_INCLUDE_PATH) $(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) mkdir -p $(INSTALL_PKGCONF_PATH) $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) @@ -313,7 +320,7 @@ mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) $(INSTALL) hiredis_ssl.h $(INSTALL_INCLUDE_PATH) $(INSTALL) $(SSL_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIBNAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIBNAME) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIB_MAJOR_NAME) $(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH) mkdir -p $(INSTALL_PKGCONF_PATH) $(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/README.md new/hiredis-1.2.0/README.md --- old/hiredis-1.1.0/README.md 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/README.md 2023-07-12 09:31:17.000000000 +0200 @@ -123,6 +123,8 @@ opt->options |= REDIS_OPT_PREFER_IPV4; ``` +If a connection is lost, `int redisReconnect(redisContext *c)` can be used to restore the connection using the same endpoint and options as the given context. + ### Configurable redisOptions flags There are several flags you may set in the `redisOptions` struct to change default behavior. You can specify the flags via the `redisOptions->options` member. @@ -138,6 +140,36 @@ *Note: A `redisContext` is not thread-safe.* +### Other configuration using socket options + +The following socket options are applied directly to the underlying socket. +The values are not stored in the `redisContext`, so they are not automatically applied when reconnecting using `redisReconnect()`. +These functions return `REDIS_OK` on success. +On failure, `REDIS_ERR` is returned and the underlying connection is closed. + +To configure these for an asyncronous context (see *Asynchronous API* below), use `ac->c` to get the redisContext out of an asyncRedisContext. + +```C +int redisEnableKeepAlive(redisContext *c); +int redisEnableKeepAliveWithInterval(redisContext *c, int interval); +``` + +Enables TCP keepalive by setting the following socket options (with some variations depending on OS): + +* `SO_KEEPALIVE`; +* `TCP_KEEPALIVE` or `TCP_KEEPIDLE`, value configurable using the `interval` parameter, default 15 seconds; +* `TCP_KEEPINTVL` set to 1/3 of `interval`; +* `TCP_KEEPCNT` set to 3. + +```C +int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout); +``` + +Set the `TCP_USER_TIMEOUT` Linux-specific socket option which is as described in the `tcp` man page: + +> When the value is greater than 0, it specifies the maximum amount of time in milliseconds that trans mitted data may remain unacknowledged before TCP will forcibly close the corresponding connection and return ETIMEDOUT to the application. +> If the option value is specified as 0, TCP will use the system default. + ### Sending commands There are several ways to issue commands to Redis. The first that will be introduced is @@ -451,7 +483,6 @@ } ``` - ### Sending commands and their callbacks In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/adapters/libsdevent.h new/hiredis-1.2.0/adapters/libsdevent.h --- old/hiredis-1.1.0/adapters/libsdevent.h 1970-01-01 01:00:00.000000000 +0100 +++ new/hiredis-1.2.0/adapters/libsdevent.h 2023-07-12 09:31:17.000000000 +0200 @@ -0,0 +1,177 @@ +#ifndef HIREDIS_LIBSDEVENT_H +#define HIREDIS_LIBSDEVENT_H +#include <systemd/sd-event.h> +#include "../hiredis.h" +#include "../async.h" + +#define REDIS_LIBSDEVENT_DELETED 0x01 +#define REDIS_LIBSDEVENT_ENTERED 0x02 + +typedef struct redisLibsdeventEvents { + redisAsyncContext *context; + struct sd_event *event; + struct sd_event_source *fdSource; + struct sd_event_source *timerSource; + int fd; + short flags; + short state; +} redisLibsdeventEvents; + +static void redisLibsdeventDestroy(redisLibsdeventEvents *e) { + if (e->fdSource) { + e->fdSource = sd_event_source_disable_unref(e->fdSource); + } + if (e->timerSource) { + e->timerSource = sd_event_source_disable_unref(e->timerSource); + } + sd_event_unref(e->event); + hi_free(e); +} + +static int redisLibsdeventTimeoutHandler(sd_event_source *s, uint64_t usec, void *userdata) { + ((void)s); + ((void)usec); + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + redisAsyncHandleTimeout(e->context); + return 0; +} + +static int redisLibsdeventHandler(sd_event_source *s, int fd, uint32_t event, void *userdata) { + ((void)s); + ((void)fd); + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + e->state |= REDIS_LIBSDEVENT_ENTERED; + +#define CHECK_DELETED() if (e->state & REDIS_LIBSDEVENT_DELETED) {\ + redisLibsdeventDestroy(e);\ + return 0; \ + } + + if ((event & EPOLLIN) && e->context && (e->state & REDIS_LIBSDEVENT_DELETED) == 0) { + redisAsyncHandleRead(e->context); + CHECK_DELETED(); + } + + if ((event & EPOLLOUT) && e->context && (e->state & REDIS_LIBSDEVENT_DELETED) == 0) { + redisAsyncHandleWrite(e->context); + CHECK_DELETED(); + } + + e->state &= ~REDIS_LIBSDEVENT_ENTERED; +#undef CHECK_DELETED + + return 0; +} + +static void redisLibsdeventAddRead(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + + if (e->flags & EPOLLIN) { + return; + } + + e->flags |= EPOLLIN; + + if (e->flags & EPOLLOUT) { + sd_event_source_set_io_events(e->fdSource, e->flags); + } else { + sd_event_add_io(e->event, &e->fdSource, e->fd, e->flags, redisLibsdeventHandler, e); + } +} + +static void redisLibsdeventDelRead(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + + e->flags &= ~EPOLLIN; + + if (e->flags) { + sd_event_source_set_io_events(e->fdSource, e->flags); + } else { + e->fdSource = sd_event_source_disable_unref(e->fdSource); + } +} + +static void redisLibsdeventAddWrite(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + + if (e->flags & EPOLLOUT) { + return; + } + + e->flags |= EPOLLOUT; + + if (e->flags & EPOLLIN) { + sd_event_source_set_io_events(e->fdSource, e->flags); + } else { + sd_event_add_io(e->event, &e->fdSource, e->fd, e->flags, redisLibsdeventHandler, e); + } +} + +static void redisLibsdeventDelWrite(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + + e->flags &= ~EPOLLOUT; + + if (e->flags) { + sd_event_source_set_io_events(e->fdSource, e->flags); + } else { + e->fdSource = sd_event_source_disable_unref(e->fdSource); + } +} + +static void redisLibsdeventCleanup(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + + if (!e) { + return; + } + + if (e->state & REDIS_LIBSDEVENT_ENTERED) { + e->state |= REDIS_LIBSDEVENT_DELETED; + } else { + redisLibsdeventDestroy(e); + } +} + +static void redisLibsdeventSetTimeout(void *userdata, struct timeval tv) { + redisLibsdeventEvents *e = (redisLibsdeventEvents *)userdata; + + uint64_t usec = tv.tv_sec * 1000000 + tv.tv_usec; + if (!e->timerSource) { + sd_event_add_time_relative(e->event, &e->timerSource, CLOCK_MONOTONIC, usec, 1, redisLibsdeventTimeoutHandler, e); + } else { + sd_event_source_set_time_relative(e->timerSource, usec); + } +} + +static int redisLibsdeventAttach(redisAsyncContext *ac, struct sd_event *event) { + redisContext *c = &(ac->c); + redisLibsdeventEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibsdeventEvents*)hi_calloc(1, sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + /* Initialize and increase event refcount */ + e->context = ac; + e->event = event; + e->fd = c->fd; + sd_event_ref(event); + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibsdeventAddRead; + ac->ev.delRead = redisLibsdeventDelRead; + ac->ev.addWrite = redisLibsdeventAddWrite; + ac->ev.delWrite = redisLibsdeventDelWrite; + ac->ev.cleanup = redisLibsdeventCleanup; + ac->ev.scheduleTimer = redisLibsdeventSetTimeout; + ac->ev.data = e; + + return REDIS_OK; +} +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/adapters/redismoduleapi.h new/hiredis-1.2.0/adapters/redismoduleapi.h --- old/hiredis-1.1.0/adapters/redismoduleapi.h 1970-01-01 01:00:00.000000000 +0100 +++ new/hiredis-1.2.0/adapters/redismoduleapi.h 2023-07-12 09:31:17.000000000 +0200 @@ -0,0 +1,144 @@ +#ifndef __HIREDIS_REDISMODULEAPI_H__ +#define __HIREDIS_REDISMODULEAPI_H__ + +#include "redismodule.h" + +#include "../async.h" +#include "../hiredis.h" + +#include <sys/types.h> + +typedef struct redisModuleEvents { + redisAsyncContext *context; + RedisModuleCtx *module_ctx; + int fd; + int reading, writing; + int timer_active; + RedisModuleTimerID timer_id; +} redisModuleEvents; + +static inline void redisModuleReadEvent(int fd, void *privdata, int mask) { + (void) fd; + (void) mask; + + redisModuleEvents *e = (redisModuleEvents*)privdata; + redisAsyncHandleRead(e->context); +} + +static inline void redisModuleWriteEvent(int fd, void *privdata, int mask) { + (void) fd; + (void) mask; + + redisModuleEvents *e = (redisModuleEvents*)privdata; + redisAsyncHandleWrite(e->context); +} + +static inline void redisModuleAddRead(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (!e->reading) { + e->reading = 1; + RedisModule_EventLoopAdd(e->fd, REDISMODULE_EVENTLOOP_READABLE, redisModuleReadEvent, e); + } +} + +static inline void redisModuleDelRead(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (e->reading) { + e->reading = 0; + RedisModule_EventLoopDel(e->fd, REDISMODULE_EVENTLOOP_READABLE); + } +} + +static inline void redisModuleAddWrite(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (!e->writing) { + e->writing = 1; + RedisModule_EventLoopAdd(e->fd, REDISMODULE_EVENTLOOP_WRITABLE, redisModuleWriteEvent, e); + } +} + +static inline void redisModuleDelWrite(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (e->writing) { + e->writing = 0; + RedisModule_EventLoopDel(e->fd, REDISMODULE_EVENTLOOP_WRITABLE); + } +} + +static inline void redisModuleStopTimer(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (e->timer_active) { + RedisModule_StopTimer(e->module_ctx, e->timer_id, NULL); + } + e->timer_active = 0; +} + +static inline void redisModuleCleanup(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + redisModuleDelRead(privdata); + redisModuleDelWrite(privdata); + redisModuleStopTimer(privdata); + hi_free(e); +} + +static inline void redisModuleTimeout(RedisModuleCtx *ctx, void *privdata) { + (void) ctx; + + redisModuleEvents *e = (redisModuleEvents*)privdata; + e->timer_active = 0; + redisAsyncHandleTimeout(e->context); +} + +static inline void redisModuleSetTimeout(void *privdata, struct timeval tv) { + redisModuleEvents* e = (redisModuleEvents*)privdata; + + redisModuleStopTimer(privdata); + + mstime_t millis = tv.tv_sec * 1000 + tv.tv_usec / 1000.0; + e->timer_id = RedisModule_CreateTimer(e->module_ctx, millis, redisModuleTimeout, e); + e->timer_active = 1; +} + +/* Check if Redis version is compatible with the adapter. */ +static inline int redisModuleCompatibilityCheck(void) { + if (!RedisModule_EventLoopAdd || + !RedisModule_EventLoopDel || + !RedisModule_CreateTimer || + !RedisModule_StopTimer) { + return REDIS_ERR; + } + return REDIS_OK; +} + +static inline int redisModuleAttach(redisAsyncContext *ac, RedisModuleCtx *module_ctx) { + redisContext *c = &(ac->c); + redisModuleEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisModuleEvents*)hi_malloc(sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + e->context = ac; + e->module_ctx = module_ctx; + e->fd = c->fd; + e->reading = e->writing = 0; + e->timer_active = 0; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisModuleAddRead; + ac->ev.delRead = redisModuleDelRead; + ac->ev.addWrite = redisModuleAddWrite; + ac->ev.delWrite = redisModuleDelWrite; + ac->ev.cleanup = redisModuleCleanup; + ac->ev.scheduleTimer = redisModuleSetTimeout; + ac->ev.data = e; + + return REDIS_OK; +} + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/examples/CMakeLists.txt new/hiredis-1.2.0/examples/CMakeLists.txt --- old/hiredis-1.1.0/examples/CMakeLists.txt 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/examples/CMakeLists.txt 2023-07-12 09:31:17.000000000 +0200 @@ -37,6 +37,12 @@ TARGET_LINK_LIBRARIES(example-libuv hiredis uv) ENDIF() +FIND_PATH(LIBSDEVENT systemd/sd-event.h) +IF (LIBSDEVENT) + ADD_EXECUTABLE(example-libsdevent example-libsdevent.c) + TARGET_LINK_LIBRARIES(example-libsdevent hiredis systemd) +ENDIF() + IF (APPLE) FIND_LIBRARY(CF CoreFoundation) ADD_EXECUTABLE(example-macosx example-macosx.c) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/examples/example-libsdevent.c new/hiredis-1.2.0/examples/example-libsdevent.c --- old/hiredis-1.1.0/examples/example-libsdevent.c 1970-01-01 01:00:00.000000000 +0100 +++ new/hiredis-1.2.0/examples/example-libsdevent.c 2023-07-12 09:31:17.000000000 +0200 @@ -0,0 +1,86 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> + +#include <hiredis.h> +#include <async.h> +#include <adapters/libsdevent.h> + +void debugCallback(redisAsyncContext *c, void *r, void *privdata) { + (void)privdata; + 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) { + 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); + + /* 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("connect error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("disconnect because of error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + + struct sd_event *event; + sd_event_default(&event); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + printf("Error: %s\n", c->errstr); + redisAsyncFree(c); + return 1; + } + + redisLibsdeventAttach(c,event); + 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 libsdevent 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"); + + /* sd-event does not quit when there are no handlers registered. Manually exit after 1.5 seconds */ + sd_event_source *s; + sd_event_add_time_relative(event, &s, CLOCK_MONOTONIC, 1500000, 1, NULL, NULL); + + sd_event_loop(event); + sd_event_source_disable_unref(s); + sd_event_unref(event); + return 0; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/examples/example-redismoduleapi.c new/hiredis-1.2.0/examples/example-redismoduleapi.c --- old/hiredis-1.1.0/examples/example-redismoduleapi.c 1970-01-01 01:00:00.000000000 +0100 +++ new/hiredis-1.2.0/examples/example-redismoduleapi.c 2023-07-12 09:31:17.000000000 +0200 @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> + +#include <hiredis.h> +#include <async.h> +#include <adapters/redismoduleapi.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) { + if (c->errstr) { + printf("errstr: %s\n", c->errstr); + } + return; + } + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* 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); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +/* + * This example requires Redis 7.0 or above. + * + * 1- Compile this file as a shared library. Directory of "redismodule.h" must + * be in the include path. + * gcc -fPIC -shared -I../../redis/src/ -I.. example-redismoduleapi.c -o example-redismoduleapi.so + * + * 2- Load module: + * redis-server --loadmodule ./example-redismoduleapi.so value + */ +int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + + int ret = RedisModule_Init(ctx, "example-redismoduleapi", 1, REDISMODULE_APIVER_1); + if (ret != REDISMODULE_OK) { + printf("error module init \n"); + return REDISMODULE_ERR; + } + + if (redisModuleCompatibilityCheck() != REDIS_OK) { + printf("Redis 7.0 or above is required! \n"); + return REDISMODULE_ERR; + } + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + size_t len; + const char *val = RedisModule_StringPtrLen(argv[argc-1], &len); + + RedisModuleCtx *module_ctx = RedisModule_GetDetachedThreadSafeContext(ctx); + redisModuleAttach(c, module_ctx); + 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 the 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", val, len); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + return 0; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/hiredis-config.cmake.in new/hiredis-1.2.0/hiredis-config.cmake.in --- old/hiredis-1.1.0/hiredis-config.cmake.in 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/hiredis-config.cmake.in 2023-07-12 09:31:17.000000000 +0200 @@ -2,11 +2,11 @@ set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@") -IF (NOT TARGET hiredis::hiredis) +IF (NOT TARGET hiredis::@hiredis_export_name@) INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake) ENDIF() -SET(hiredis_LIBRARIES hiredis::hiredis) +SET(hiredis_LIBRARIES hiredis::@hiredis_export_name@) SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR}) check_required_components(hiredis) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/hiredis.c new/hiredis-1.2.0/hiredis.c --- old/hiredis-1.1.0/hiredis.c 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/hiredis.c 2023-07-12 09:31:17.000000000 +0200 @@ -392,12 +392,12 @@ while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; /* Field width */ - while (*_p != '\0' && isdigit(*_p)) _p++; + while (*_p != '\0' && isdigit((int) *_p)) _p++; /* Precision */ if (*_p == '.') { _p++; - while (*_p != '\0' && isdigit(*_p)) _p++; + while (*_p != '\0' && isdigit((int) *_p)) _p++; } /* Copy va_list before consuming with va_arg */ @@ -860,7 +860,9 @@ return NULL; } - if (options->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) { + if (c->err == 0 && c->fd != REDIS_INVALID_FD && + options->command_timeout != NULL && (c->flags & REDIS_BLOCK)) + { redisContextSetTimeout(c, *options->command_timeout); } @@ -942,11 +944,18 @@ return REDIS_ERR; } +int redisEnableKeepAliveWithInterval(redisContext *c, int interval) { + return redisKeepAlive(c, interval); +} + /* Enable connection KeepAlive. */ int redisEnableKeepAlive(redisContext *c) { - if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK) - return REDIS_ERR; - return REDIS_OK; + return redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL); +} + +/* Set the socket option TCP_USER_TIMEOUT. */ +int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout) { + return redisContextSetTcpUserTimeout(c, timeout); } /* Set a user provided RESP3 PUSH handler and return any old one set. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/hiredis.h new/hiredis-1.2.0/hiredis.h --- old/hiredis-1.1.0/hiredis.h 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/hiredis.h 2023-07-12 09:31:17.000000000 +0200 @@ -46,7 +46,7 @@ #include "alloc.h" /* for allocation wrappers */ #define HIREDIS_MAJOR 1 -#define HIREDIS_MINOR 1 +#define HIREDIS_MINOR 2 #define HIREDIS_PATCH 0 #define HIREDIS_SONAME 1.1.0 @@ -154,24 +154,18 @@ #define REDIS_OPT_NONBLOCK 0x01 #define REDIS_OPT_REUSEADDR 0x02 -#define REDIS_OPT_PREFER_IPV4 0x04 -#define REDIS_OPT_PREFER_IPV6 0x08 +#define REDIS_OPT_NOAUTOFREE 0x04 /* Don't automatically free the async + * object on a connection failure, or + * other implicit conditions. Only free + * on an explicit call to disconnect() + * or free() */ +#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08 /* Don't automatically intercept and + * free RESP3 PUSH replies. */ +#define REDIS_OPT_NOAUTOFREEREPLIES 0x10 /* Don't automatically free replies. */ +#define REDIS_OPT_PREFER_IPV4 0x20 /* Prefer IPv4 in DNS lookups. */ +#define REDIS_OPT_PREFER_IPV6 0x40 /* Prefer IPv6 in DNS lookups. */ #define REDIS_OPT_PREFER_IP_UNSPEC (REDIS_OPT_PREFER_IPV4 | REDIS_OPT_PREFER_IPV6) -/** - * Don't automatically free the async object on a connection failure, - * or other implicit conditions. Only free on an explicit call to disconnect() or free() - */ -#define REDIS_OPT_NOAUTOFREE 0x04 - -/* Don't automatically intercept and free RESP3 PUSH replies. */ -#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08 - -/** - * 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 @@ -328,6 +322,8 @@ redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); int redisSetTimeout(redisContext *c, const struct timeval tv); int redisEnableKeepAlive(redisContext *c); +int redisEnableKeepAliveWithInterval(redisContext *c, int interval); +int redisSetTcpUserTimeout(redisContext *c, unsigned int timeout); void redisFree(redisContext *c); redisFD redisFreeKeepFd(redisContext *c); int redisBufferRead(redisContext *c); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/hiredis_ssl-config.cmake.in new/hiredis-1.2.0/hiredis_ssl-config.cmake.in --- old/hiredis-1.1.0/hiredis_ssl-config.cmake.in 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/hiredis_ssl-config.cmake.in 2023-07-12 09:31:17.000000000 +0200 @@ -2,6 +2,9 @@ set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +include(CMakeFindDependencyMacro) +find_dependency(OpenSSL) + IF (NOT TARGET hiredis::hiredis_ssl) INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake) ENDIF() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/hiredis_ssl.h new/hiredis-1.2.0/hiredis_ssl.h --- old/hiredis-1.1.0/hiredis_ssl.h 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/hiredis_ssl.h 2023-07-12 09:31:17.000000000 +0200 @@ -58,7 +58,7 @@ REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ REDIS_SSL_CTX_CLIENT_DEFAULT_CERT_FAILED, /* Failed to set client default certificate directory */ 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_CERTSTORE_OPEN_FAILED, /* Failed to open system certificate store */ REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */ } redisSSLContextError; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/net.c new/hiredis-1.2.0/net.c --- old/hiredis-1.1.0/net.c 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/net.c 2023-07-12 09:31:17.000000000 +0200 @@ -228,6 +228,23 @@ return REDIS_OK; } +int redisContextSetTcpUserTimeout(redisContext *c, unsigned int timeout) { + int res; +#ifdef TCP_USER_TIMEOUT + res = setsockopt(c->fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout)); +#else + res = -1; + errno = ENOTSUP; + (void)timeout; +#endif + if (res == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_USER_TIMEOUT)"); + redisNetClose(c); + return REDIS_ERR; + } + return REDIS_OK; +} + #define __MAX_MSEC (((LONG_MAX) - 999) / 1000) static int redisContextTimeoutMsec(redisContext *c, long *result) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/net.h new/hiredis-1.2.0/net.h --- old/hiredis-1.1.0/net.h 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/net.h 2023-07-12 09:31:17.000000000 +0200 @@ -52,5 +52,6 @@ int redisCheckConnectDone(redisContext *c, int *completed); int redisSetTcpNoDelay(redisContext *c); +int redisContextSetTcpUserTimeout(redisContext *c, unsigned int timeout); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/read.c new/hiredis-1.2.0/read.c --- old/hiredis-1.1.0/read.c 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/read.c 2023-07-12 09:31:17.000000000 +0200 @@ -303,7 +303,8 @@ d = INFINITY; /* Positive infinite. */ } else if (len == 4 && strcasecmp(buf,"-inf") == 0) { d = -INFINITY; /* Negative infinite. */ - } else if (len == 3 && strcasecmp(buf,"nan") == 0) { + } else if ((len == 3 && strcasecmp(buf,"nan") == 0) || + (len == 4 && strcasecmp(buf, "-nan") == 0)) { d = NAN; /* nan. */ } else { d = strtod((char*)buf,&eptr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/sds.c new/hiredis-1.2.0/sds.c --- old/hiredis-1.1.0/sds.c 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/sds.c 2023-07-12 09:31:17.000000000 +0200 @@ -886,7 +886,7 @@ case '\a': s = sdscatlen(s,"\\a",2); break; case '\b': s = sdscatlen(s,"\\b",2); break; default: - if (isprint(*p)) + if (isprint((int) *p)) s = sdscatprintf(s,"%c",*p); else s = sdscatprintf(s,"\\x%02x",(unsigned char)*p); @@ -948,7 +948,7 @@ *argc = 0; while(1) { /* skip blanks */ - while(*p && isspace(*p)) p++; + while(*p && isspace((int) *p)) p++; if (*p) { /* get a token */ int inq=0; /* set to 1 if we are in "quotes" */ @@ -959,8 +959,8 @@ while(!done) { if (inq) { if (*p == '\\' && *(p+1) == 'x' && - isxdigit(*(p+2)) && - isxdigit(*(p+3))) + isxdigit((int) *(p+2)) && + isxdigit((int) *(p+3))) { unsigned char byte; @@ -984,7 +984,7 @@ } else if (*p == '"') { /* closing quote must be followed by a space or * nothing at all. */ - if (*(p+1) && !isspace(*(p+1))) goto err; + if (*(p+1) && !isspace((int) *(p+1))) goto err; done=1; } else if (!*p) { /* unterminated quotes */ @@ -999,7 +999,7 @@ } else if (*p == '\'') { /* closing quote must be followed by a space or * nothing at all. */ - if (*(p+1) && !isspace(*(p+1))) goto err; + if (*(p+1) && !isspace((int) *(p+1))) goto err; done=1; } else if (!*p) { /* unterminated quotes */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/ssl.c new/hiredis-1.2.0/ssl.c --- old/hiredis-1.1.0/ssl.c 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/ssl.c 2023-07-12 09:31:17.000000000 +0200 @@ -40,6 +40,14 @@ #ifdef _WIN32 #include <windows.h> #include <wincrypt.h> +#ifdef OPENSSL_IS_BORINGSSL +#undef X509_NAME +#undef X509_EXTENSIONS +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#undef OCSP_REQUEST +#undef OCSP_RESPONSE +#endif #else #include <pthread.h> #endif @@ -51,6 +59,8 @@ #include "async_private.h" #include "hiredis_ssl.h" +#define OPENSSL_1_1_0 0x10100000L + void __redisSetError(redisContext *c, int type, const char *str); struct redisSSLContext { @@ -92,7 +102,7 @@ * Note that this is only required for OpenSSL < 1.1.0. */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < OPENSSL_1_1_0 #define HIREDIS_USE_CRYPTO_LOCKS #endif @@ -185,7 +195,7 @@ 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"; + return "Failed to open system certificate store"; case REDIS_SSL_CTX_OS_CERT_ADD_FAILED: return "Failed to add CA certificates obtained from system to the SSL context"; default: @@ -248,13 +258,25 @@ if (ctx == NULL) goto error; - ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + const SSL_METHOD *ssl_method; +#if OPENSSL_VERSION_NUMBER >= OPENSSL_1_1_0 + ssl_method = TLS_client_method(); +#else + ssl_method = SSLv23_client_method(); +#endif + + ctx->ssl_ctx = SSL_CTX_new(ssl_method); if (!ctx->ssl_ctx) { if (error) *error = REDIS_SSL_CTX_CREATE_FAILED; goto error; } - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); +#if OPENSSL_VERSION_NUMBER >= OPENSSL_1_1_0 + SSL_CTX_set_min_proto_version(ctx->ssl_ctx, TLS1_2_VERSION); +#else + SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); +#endif + SSL_CTX_set_verify(ctx->ssl_ctx, options->verify_mode, NULL); if ((cert_filename != NULL && private_key_filename == NULL) || diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hiredis-1.1.0/test.c new/hiredis-1.2.0/test.c --- old/hiredis-1.1.0/test.c 2022-11-15 05:34:30.000000000 +0100 +++ new/hiredis-1.2.0/test.c 2023-07-12 09:31:17.000000000 +0200 @@ -78,7 +78,7 @@ static void millisleep(int ms) { -#if _MSC_VER +#ifdef _MSC_VER Sleep(ms); #else usleep(ms*1000); @@ -409,10 +409,19 @@ redisContext *c; c = do_connect(cfg); + test("We can enable TCP_KEEPALIVE: "); test_cond(redisEnableKeepAlive(c) == REDIS_OK); - disconnect(c, 0); +#ifdef TCP_USER_TIMEOUT + test("We can set TCP_USER_TIMEOUT: "); + test_cond(redisSetTcpUserTimeout(c, 100) == REDIS_OK); +#else + test("Setting TCP_USER_TIMEOUT errors when unsupported: "); + test_cond(redisSetTcpUserTimeout(c, 100) == REDIS_ERR && c->err == REDIS_ERR_IO); +#endif + + redisFree(c); } static void test_reply_reader(void) { @@ -684,6 +693,16 @@ freeReplyObject(reply); redisReaderFree(reader); + test("Correctly parses RESP3 double -Nan: "); + reader = redisReaderCreate(); + redisReaderFeed(reader, ",-nan\r\n", 7); + ret = redisReaderGetReply(reader, &reply); + test_cond(ret == REDIS_OK && + ((redisReply*)reply)->type == REDIS_REPLY_DOUBLE && + isnan(((redisReply*)reply)->dval)); + freeReplyObject(reply); + redisReaderFree(reader); + test("Can parse RESP3 nil: "); reader = redisReaderCreate(); redisReaderFeed(reader, "_\r\n",3); @@ -871,9 +890,9 @@ #define HIREDIS_BAD_DOMAIN "idontexist-noreally.com" static void test_blocking_connection_errors(void) { - redisContext *c; struct addrinfo hints = {.ai_family = AF_INET}; struct addrinfo *ai_tmp = NULL; + redisContext *c; int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp); if (rv != 0) { @@ -900,12 +919,26 @@ } #ifndef _WIN32 + redisOptions opt = {0}; + struct timeval tv; + test("Returns error when the port is not open: "); c = redisConnect((char*)"localhost", 1); test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr,"Connection refused") == 0); redisFree(c); + + /* Verify we don't regress from the fix in PR #1180 */ + test("We don't clobber connection exception with setsockopt error: "); + tv = (struct timeval){.tv_sec = 0, .tv_usec = 500000}; + opt.command_timeout = opt.connect_timeout = &tv; + REDIS_OPTIONS_SET_TCP(&opt, "localhost", 10337); + c = redisConnectWithOptions(&opt); + test_cond(c->err == REDIS_ERR_IO && + strcmp(c->errstr, "Connection refused") == 0); + redisFree(c); + test("Returns error when the unix_sock socket path doesn't accept connections: "); c = redisConnectUnix((char*)"/tmp/idontexist.sock"); test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */ @@ -1543,6 +1576,9 @@ // } #ifdef HIREDIS_TEST_ASYNC + +#pragma GCC diagnostic ignored "-Woverlength-strings" /* required on gcc 4.8.x due to assert statements */ + struct event_base *base; typedef struct TestState {
