From 31d934d19bf82efdfc320fa7008008242a65332a Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Fri, 22 Mar 2024 20:06:01 +0100 Subject: all: rename output files Signed-off-by: Anna (navi) Figueiredo Gomes --- .gitignore | 1 + .reuse/dep5 | 6 +- CMakeLists.txt | 160 ++--- Makefile | 120 ++-- adapters/ae.h | 2 +- adapters/glib.h | 2 +- adapters/ivykis.h | 2 +- adapters/libev.h | 2 +- adapters/libevent.h | 2 +- adapters/libhv.h | 2 +- adapters/libsdevent.h | 2 +- adapters/libuv.h | 2 +- adapters/macosx.h | 2 +- adapters/redismoduleapi.h | 2 +- async.h | 2 +- examples/example-ae.c | 2 +- examples/example-glib.c | 2 +- examples/example-ivykis.c | 2 +- examples/example-libev.c | 2 +- examples/example-libevent-ssl.c | 2 +- examples/example-libevent.c | 2 +- examples/example-libhv.c | 2 +- examples/example-libsdevent.c | 2 +- examples/example-libuv.c | 2 +- examples/example-macosx.c | 2 +- examples/example-push.c | 2 +- examples/example-redismoduleapi.c | 2 +- examples/example-ssl.c | 2 +- examples/example.c | 2 +- fuzzing/format_command_fuzzer.c | 2 +- hiredict-config.cmake.in | 13 + hiredict.c | 1210 +++++++++++++++++++++++++++++++++++++ hiredict.h | 346 +++++++++++ hiredict.pc.in | 12 + hiredict.targets | 11 + hiredict_ssl-config.cmake.in | 16 + hiredict_ssl.h | 143 +++++ hiredict_ssl.pc.in | 13 + hiredis-config.cmake.in | 13 - hiredis.c | 1210 ------------------------------------- hiredis.h | 346 ----------- hiredis.pc.in | 12 - hiredis.targets | 11 - hiredis_ssl-config.cmake.in | 16 - hiredis_ssl.h | 143 ----- hiredis_ssl.pc.in | 13 - net.h | 2 +- ssl.c | 2 +- test.c | 2 +- 49 files changed, 1937 insertions(+), 1936 deletions(-) create mode 100644 hiredict-config.cmake.in create mode 100644 hiredict.c create mode 100644 hiredict.h create mode 100644 hiredict.pc.in create mode 100644 hiredict.targets create mode 100644 hiredict_ssl-config.cmake.in create mode 100644 hiredict_ssl.h create mode 100644 hiredict_ssl.pc.in delete mode 100644 hiredis-config.cmake.in delete mode 100644 hiredis.c delete mode 100644 hiredis.h delete mode 100644 hiredis.pc.in delete mode 100644 hiredis.targets delete mode 100644 hiredis_ssl-config.cmake.in delete mode 100644 hiredis_ssl.h delete mode 100644 hiredis_ssl.pc.in diff --git a/.gitignore b/.gitignore index c223f29..732ac56 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /*.dylib /*.a /*.pc +build/ *.dSYM tags compile_commands.json diff --git a/.reuse/dep5 b/.reuse/dep5 index 8c2a37e..72e39a8 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -13,15 +13,15 @@ Files: .gitignore .travis.yml appveyor.yml Copyright: Salvatore Sanfilippo License: BSD-3-Clause -Files: hiredis.pc.in hiredis.targets hiredis_ssl.pc.in +Files: hiredict.pc.in hiredict.targets hiredict_ssl.pc.in Copyright: Salvatore Sanfilippo License: BSD-3-Clause -Files: hiredis-config.cmake.in hiredis_ssl-config.cmake.in +Files: hiredict-config.cmake.in hiredict_ssl-config.cmake.in Copyright: Salvatore Sanfilippo License: BSD-3-Clause -Files: hiredis.targets +Files: hiredict.targets Copyright: Salvatore Sanfilippo License: BSD-3-Clause diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f12937..195934f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0) MACRO(getVersionBit name) SET(VERSION_REGEX "^#define ${name} (.+)$") - FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredis.h" + FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredict.h" VERSION_BIT REGEX ${VERSION_REGEX}) STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}") ENDMACRO(getVersionBit) @@ -20,139 +20,138 @@ getVersionBit(HIREDIS_SONAME) SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}") MESSAGE("Detected version: ${VERSION}") -PROJECT(hiredis LANGUAGES "C" VERSION "${VERSION}") +PROJECT(hiredict LANGUAGES "C" VERSION "${VERSION}") INCLUDE(GNUInstallDirs) OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON) -OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF) +OPTION(ENABLE_SSL "Build hiredict_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_EXAMPLES "Enable building hiredict examples" OFF) OPTION(ENABLE_ASYNC_TESTS "Should we run all asynchronous API tests" OFF) # Historically, the NuGet file was always install; default # to ON for those who rely on that historical behaviour. OPTION(ENABLE_NUGET "Install NuGET packaging details" ON) -# Hiredis requires C99 +# Hiredict requires C99 SET(CMAKE_C_STANDARD 99) SET(CMAKE_DEBUG_POSTFIX d) -SET(hiredis_sources +SET(hiredict_sources alloc.c async.c - hiredis.c + hiredict.c net.c read.c sds.c sockcompat.c) -SET(hiredis_sources ${hiredis_sources}) +SET(hiredict_sources ${hiredict_sources}) IF(WIN32) ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN) ENDIF() -ADD_LIBRARY(hiredis ${hiredis_sources}) -ADD_LIBRARY(hiredis::hiredis ALIAS hiredis) -set(hiredis_export_name hiredis CACHE STRING "Name of the exported target") -set_target_properties(hiredis PROPERTIES EXPORT_NAME ${hiredis_export_name}) +ADD_LIBRARY(hiredict ${hiredict_sources}) +ADD_LIBRARY(hiredict::hiredict ALIAS hiredict) +set(hiredict_export_name hiredict CACHE STRING "Name of the exported target") +set_target_properties(hiredict PROPERTIES EXPORT_NAME ${hiredict_export_name}) -SET_TARGET_PROPERTIES(hiredis +SET_TARGET_PROPERTIES(hiredict PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE - VERSION "${HIREDIS_SONAME}") + VERSION "${HIREDIS_SONAME}") IF(MSVC) - SET_TARGET_PROPERTIES(hiredis + SET_TARGET_PROPERTIES(hiredict PROPERTIES COMPILE_FLAGS /Z7) ENDIF() IF(WIN32) - TARGET_LINK_LIBRARIES(hiredis PUBLIC ws2_32 crypt32) + TARGET_LINK_LIBRARIES(hiredict PUBLIC ws2_32 crypt32) ELSEIF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - TARGET_LINK_LIBRARIES(hiredis PUBLIC m) + TARGET_LINK_LIBRARIES(hiredict PUBLIC m) ELSEIF(CMAKE_SYSTEM_NAME MATCHES "SunOS") - TARGET_LINK_LIBRARIES(hiredis PUBLIC socket) + TARGET_LINK_LIBRARIES(hiredict PUBLIC socket) ENDIF() -TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $ $) +TARGET_INCLUDE_DIRECTORIES(hiredict PUBLIC $ $) -CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY) +CONFIGURE_FILE(hiredict.pc.in hiredict.pc @ONLY) -set(CPACK_PACKAGE_VENDOR "Redis") +set(CPACK_PACKAGE_VENDOR "Redict") set(CPACK_PACKAGE_DESCRIPTION "\ -Hiredis is a minimalistic C client library for the Redis database. +Hiredict is a minimalistic C client library for the Redict database. It is minimalistic because it just adds minimal support for the protocol, \ but at the same time it uses a high level printf-alike API in order to make \ it much higher level than otherwise suggested by its minimal code base and the \ -lack of explicit bindings for every Redis command. +lack of explicit bindings for every Redict command. Apart from supporting sending commands and receiving replies, it comes with a \ reply parser that is decoupled from the I/O layer. It is a stream parser designed \ for easy reusability, which can for instance be used in higher level language bindings \ for efficient reply parsing. -Hiredis only supports the binary-safe Redis protocol, so you can use it with any Redis \ -version >= 1.2.0. +Hiredict only supports the binary-safe Redis protocol. The library comes with multiple APIs. There is the synchronous API, the asynchronous API \ and the reply parsing API.") -set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/redis/hiredis") -set(CPACK_PACKAGE_CONTACT "michael dot grunder at gmail dot com") +set(CPACK_PACKAGE_HOMEPAGE_URL "https://codeberg.org/redict/hiredict") +set(CPACK_PACKAGE_CONTACT "navi@vlhl.dev") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_RPM_PACKAGE_AUTOREQPROV ON) include(CPack) -INSTALL(TARGETS hiredis - EXPORT hiredis-targets +INSTALL(TARGETS hiredict + EXPORT hiredict-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) if (MSVC AND BUILD_SHARED_LIBS) - INSTALL(FILES $ + INSTALL(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo) endif() if (ENABLE_NUGET) # For NuGet packages - INSTALL(FILES hiredis.targets + INSTALL(FILES hiredict.targets DESTINATION build/native) endif() -INSTALL(FILES hiredis.h read.h sds.h async.h alloc.h sockcompat.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) +INSTALL(FILES hiredict.h read.h sds.h async.h alloc.h sockcompat.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredict) INSTALL(DIRECTORY adapters - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredict) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredict.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -export(EXPORT hiredis-targets - FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis-targets.cmake" - NAMESPACE hiredis::) +export(EXPORT hiredict-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredict-targets.cmake" + NAMESPACE hiredict::) if(WIN32) - SET(CMAKE_CONF_INSTALL_DIR share/hiredis) + SET(CMAKE_CONF_INSTALL_DIR share/hiredict) else() - SET(CMAKE_CONF_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/hiredis) + SET(CMAKE_CONF_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/hiredict) endif() SET(INCLUDE_INSTALL_DIR include) include(CMakePackageConfigHelpers) -write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/hiredis-config-version.cmake" +write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/hiredict-config-version.cmake" COMPATIBILITY SameMajorVersion) -configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake +configure_package_config_file(hiredict-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredict-config.cmake INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR) -INSTALL(EXPORT hiredis-targets - FILE hiredis-targets.cmake - NAMESPACE hiredis:: +INSTALL(EXPORT hiredict-targets + FILE hiredict-targets.cmake + NAMESPACE hiredict:: DESTINATION ${CMAKE_CONF_INSTALL_DIR}) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config-version.cmake +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredict-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/hiredict-config-version.cmake DESTINATION ${CMAKE_CONF_INSTALL_DIR}) @@ -163,82 +162,83 @@ IF(ENABLE_SSL) ENDIF() ENDIF() FIND_PACKAGE(OpenSSL REQUIRED) - SET(hiredis_ssl_sources + SET(hiredict_ssl_sources ssl.c) - ADD_LIBRARY(hiredis_ssl ${hiredis_ssl_sources}) - ADD_LIBRARY(hiredis::hiredis_ssl ALIAS hiredis_ssl) + ADD_LIBRARY(hiredict_ssl ${hiredict_ssl_sources}) + ADD_LIBRARY(hiredict::hiredict_ssl ALIAS hiredict_ssl) IF (APPLE AND BUILD_SHARED_LIBS) - SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup") + SET_PROPERTY(TARGET hiredict_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup") ENDIF() - SET_TARGET_PROPERTIES(hiredis_ssl + SET_TARGET_PROPERTIES(hiredict_ssl PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE - VERSION "${HIREDIS_SONAME}") + VERSION "${HIREDIS_SONAME}") IF(MSVC) - SET_TARGET_PROPERTIES(hiredis_ssl + SET_TARGET_PROPERTIES(hiredict_ssl PROPERTIES COMPILE_FLAGS /Z7) ENDIF() - TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE OpenSSL::SSL) + TARGET_LINK_LIBRARIES(hiredict_ssl PRIVATE OpenSSL::SSL) IF(WIN32) - TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis) + TARGET_LINK_LIBRARIES(hiredict_ssl PRIVATE hiredict) ENDIF() - CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY) + CONFIGURE_FILE(hiredict_ssl.pc.in hiredict_ssl.pc @ONLY) - INSTALL(TARGETS hiredis_ssl - EXPORT hiredis_ssl-targets + INSTALL(TARGETS hiredict_ssl + EXPORT hiredict_ssl-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) if (MSVC AND BUILD_SHARED_LIBS) - INSTALL(FILES $ + INSTALL(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS Debug RelWithDebInfo) endif() - INSTALL(FILES hiredis_ssl.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) + INSTALL(FILES hiredict_ssl.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredict) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredict_ssl.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - export(EXPORT hiredis_ssl-targets - FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-targets.cmake" - NAMESPACE hiredis::) + export(EXPORT hiredict_ssl-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredict_ssl-targets.cmake" + NAMESPACE hiredict::) if(WIN32) - SET(CMAKE_CONF_INSTALL_DIR share/hiredis_ssl) + SET(CMAKE_CONF_INSTALL_DIR share/hiredict_ssl) else() - SET(CMAKE_CONF_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/hiredis_ssl) + SET(CMAKE_CONF_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/hiredict_ssl) endif() - configure_package_config_file(hiredis_ssl-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake + configure_package_config_file(hiredict_ssl-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/hiredict_ssl-config.cmake INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR) - INSTALL(EXPORT hiredis_ssl-targets - FILE hiredis_ssl-targets.cmake - NAMESPACE hiredis:: + INSTALL(EXPORT hiredict_ssl-targets + FILE hiredict_ssl-targets.cmake + NAMESPACE hiredict:: DESTINATION ${CMAKE_CONF_INSTALL_DIR}) - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredict_ssl-config.cmake DESTINATION ${CMAKE_CONF_INSTALL_DIR}) ENDIF() IF(NOT DISABLE_TESTS) ENABLE_TESTING() - ADD_EXECUTABLE(hiredis-test test.c) - TARGET_LINK_LIBRARIES(hiredis-test hiredis) + ADD_EXECUTABLE(hiredict-test test.c) + TARGET_LINK_LIBRARIES(hiredict-test hiredict) IF(ENABLE_SSL_TESTS) - ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1) - TARGET_LINK_LIBRARIES(hiredis-test hiredis_ssl) + ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1) + TARGET_LINK_LIBRARIES(hiredict-test hiredict_ssl) ENDIF() IF(ENABLE_ASYNC_TESTS) - ADD_DEFINITIONS(-DHIREDIS_TEST_ASYNC=1) - TARGET_LINK_LIBRARIES(hiredis-test event) + ADD_DEFINITIONS(-DHIREDIS_TEST_ASYNC=1) + TARGET_LINK_LIBRARIES(hiredict-test event) ENDIF() - ADD_TEST(NAME hiredis-test + ADD_TEST(NAME hiredict-test COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh) ENDIF() diff --git a/Makefile b/Makefile index 3bdb970..58e2832 100644 --- a/Makefile +++ b/Makefile @@ -9,35 +9,35 @@ # SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: LGPL-3.0-or-later -OBJ=alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o -EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push hiredis-example-poll -TESTS=hiredis-test -LIBNAME=libhiredis -PKGCONFNAME=hiredis.pc +OBJ=alloc.o net.o hiredict.o sds.o async.o read.o sockcompat.o +EXAMPLES=hiredict-example hiredict-example-libevent hiredict-example-libev hiredict-example-glib hiredict-example-push hiredict-example-poll +TESTS=hiredict-test +LIBNAME=libhiredict +PKGCONFNAME=hiredict.pc -HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}') -HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}') -HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}') -HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}') +HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredict.h | awk '{print $$3}') +HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredict.h | awk '{print $$3}') +HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredict.h | awk '{print $$3}') +HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredict.h | awk '{print $$3}') # Installation related variables and target PREFIX?=/usr/local -INCLUDE_PATH?=include/hiredis +INCLUDE_PATH?=include/hiredict LIBRARY_PATH?=lib PKGCONF_PATH?=pkgconfig INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH) INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH) -# redis-server configuration used for testing +# redict-server configuration used for testing REDIS_PORT=56379 -REDIS_SERVER=redis-server +REDIS_SERVER=redict-server define REDIS_TEST_CONFIG daemonize yes - pidfile /tmp/hiredis-test-redis.pid + pidfile /tmp/hiredict-test-redict.pid port $(REDIS_PORT) bind 127.0.0.1 - unixsocket /tmp/hiredis-test-redis.sock + unixsocket /tmp/hiredict-test-redict.sock endef export REDIS_TEST_CONFIG @@ -66,8 +66,8 @@ STLIB_MAKE_CMD=$(AR) rcs #################### SSL variables start #################### SSL_OBJ=ssl.o -SSL_LIBNAME=libhiredis_ssl -SSL_PKGCONFNAME=hiredis_ssl.pc +SSL_LIBNAME=libhiredict_ssl +SSL_PKGCONFNAME=hiredict_ssl.pc SSL_INSTALLNAME=install-ssl SSL_DYLIB_MINOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) SSL_DYLIB_MAJOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR) @@ -79,7 +79,7 @@ USE_SSL?=0 ifeq ($(USE_SSL),1) # This is required for test.c only CFLAGS+=-DHIREDIS_TEST_SSL - EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl + EXAMPLES+=hiredict-example-ssl hiredict-example-libevent-ssl SSL_STLIB=$(SSL_STLIBNAME) SSL_DYLIB=$(SSL_DYLIBNAME) SSL_PKGCONF=$(SSL_PKGCONFNAME) @@ -152,7 +152,7 @@ ifeq ($(uname_S),Darwin) DYLIB_PLUGIN=-Wl,-undefined -Wl,dynamic_lookup endif -all: dynamic static hiredis-test pkgconfig +all: dynamic static hiredict-test pkgconfig dynamic: $(DYLIBNAME) $(SSL_DYLIB) @@ -162,14 +162,14 @@ pkgconfig: $(PKGCONFNAME) $(SSL_PKGCONF) # Deps (use make dep to generate this) alloc.o: alloc.c fmacros.h alloc.h -async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h +async.o: async.c fmacros.h alloc.h async.h hiredict.h read.h sds.h net.h dict.c dict.h win32.h async_private.h dict.o: dict.c fmacros.h alloc.h dict.h -hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h +hiredict.o: hiredict.c fmacros.h hiredict.h read.h sds.h alloc.h net.h async.h win32.h +net.o: net.c fmacros.h net.h hiredict.h read.h sds.h alloc.h sockcompat.h win32.h read.o: read.c fmacros.h alloc.h read.h sds.h win32.h sds.o: sds.c sds.h sdsalloc.h alloc.h sockcompat.o: sockcompat.c sockcompat.h -test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h sockcompat.h win32.h +test.o: test.c fmacros.h hiredict.h read.h sds.h alloc.h net.h sockcompat.h win32.h $(DYLIBNAME): $(OBJ) $(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS) @@ -184,62 +184,62 @@ $(SSL_DYLIBNAME): $(SSL_OBJ) $(SSL_STLIBNAME): $(SSL_OBJ) $(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ) -$(SSL_OBJ): ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h +$(SSL_OBJ): ssl.c hiredict.h read.h sds.h alloc.h async.h win32.h async_private.h #################### SSL building rules end #################### # Binaries: -hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) +hiredict-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME) +hiredict-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS) -hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) +hiredict-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-libhv: examples/example-libhv.c adapters/libhv.h $(STLIBNAME) +hiredict-example-libhv: examples/example-libhv.c adapters/libhv.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lhv $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) +hiredict-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) +hiredict-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) +hiredict-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME) +hiredict-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS) -hiredis-example-poll: examples/example-poll.c adapters/poll.h $(STLIBNAME) +hiredict-example-poll: examples/example-poll.c adapters/poll.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) ifndef AE_DIR -hiredis-example-ae: - @echo "Please specify AE_DIR (e.g. /src)" +hiredict-example-ae: + @echo "Please specify AE_DIR (e.g. /src)" @false else -hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) +hiredict-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME) endif ifndef LIBUV_DIR # dynamic link libuv.so -hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) +hiredict-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< -luv -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS) else # use user provided static lib -hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) +hiredict-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS) endif ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),) -hiredis-example-qt: +hiredict-example-qt: @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR" @false else -hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) +hiredict-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ @@ -247,10 +247,10 @@ hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) $(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore endif -hiredis-example: examples/example.c $(STLIBNAME) +hiredict-example: examples/example.c $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) -hiredis-example-push: examples/example-push.c $(STLIBNAME) +hiredict-example-push: examples/example-push.c $(STLIBNAME) $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) examples: $(EXAMPLES) @@ -264,30 +264,30 @@ ifeq ($(TEST_ASYNC),1) TEST_LDFLAGS += -levent endif -hiredis-test: test.o $(TEST_LIBS) +hiredict-test: test.o $(TEST_LIBS) $(CC) -o $@ $(REAL_CFLAGS) -I. $^ $(REAL_LDFLAGS) $(TEST_LDFLAGS) -hiredis-%: %.o $(STLIBNAME) +hiredict-%: %.o $(STLIBNAME) $(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS) -test: hiredis-test - ./hiredis-test +test: hiredict-test + ./hiredict-test -check: hiredis-test +check: hiredict-test TEST_SSL=$(USE_SSL) ./test.sh .c.o: $(CC) -std=c99 -c $(REAL_CFLAGS) $< clean: - rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov + rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredict-example* *.o *.gcda *.gcno *.gcov dep: $(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c INSTALL?= cp -pPR -$(PKGCONFNAME): hiredis.h +$(PKGCONFNAME): hiredict.h @echo "Generating $@ for pkgconfig..." @echo prefix=$(PREFIX) > $@ @echo exec_prefix=\$${prefix} >> $@ @@ -295,13 +295,13 @@ $(PKGCONFNAME): hiredis.h @echo includedir=$(PREFIX)/include >> $@ @echo pkgincludedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ @echo >> $@ - @echo Name: hiredis >> $@ + @echo Name: hiredict >> $@ @echo Description: Minimalistic C client library for Redis. >> $@ @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ - @echo Libs: -L\$${libdir} -lhiredis >> $@ + @echo Libs: -L\$${libdir} -lhiredict >> $@ @echo Cflags: -I\$${pkgincludedir} -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ -$(SSL_PKGCONFNAME): hiredis_ssl.h +$(SSL_PKGCONFNAME): hiredict_ssl.h @echo "Generating $@ for pkgconfig..." @echo prefix=$(PREFIX) > $@ @echo exec_prefix=\$${prefix} >> $@ @@ -309,16 +309,16 @@ $(SSL_PKGCONFNAME): hiredis_ssl.h @echo includedir=$(PREFIX)/include >> $@ @echo pkgincludedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ @echo >> $@ - @echo Name: hiredis_ssl >> $@ - @echo Description: SSL Support for hiredis. >> $@ + @echo Name: hiredict_ssl >> $@ + @echo Description: SSL Support for hiredict. >> $@ @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ - @echo Requires: hiredis >> $@ - @echo Libs: -L\$${libdir} -lhiredis_ssl >> $@ + @echo Requires: hiredict >> $@ + @echo Libs: -L\$${libdir} -lhiredict_ssl >> $@ @echo Libs.private: -lssl -lcrypto >> $@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) $(SSL_INSTALL) mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis.h async.h read.h sds.h alloc.h sockcompat.h $(INSTALL_INCLUDE_PATH) + $(INSTALL) hiredict.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) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) @@ -328,7 +328,7 @@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) $(SSL_INSTALL) install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME) mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis_ssl.h $(INSTALL_INCLUDE_PATH) + $(INSTALL) hiredict_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) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIB_MAJOR_NAME) $(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH) @@ -354,9 +354,9 @@ gcov: coverage: gcov make check mkdir -p tmp/lcov - lcov -d . -c --exclude '/usr*' -o tmp/lcov/hiredis.info - lcov -q -l tmp/lcov/hiredis.info - genhtml --legend -q -o tmp/lcov/report tmp/lcov/hiredis.info + lcov -d . -c --exclude '/usr*' -o tmp/lcov/hiredict.info + lcov -q -l tmp/lcov/hiredict.info + genhtml --legend -q -o tmp/lcov/report tmp/lcov/hiredict.info noopt: $(MAKE) OPTIMIZATION="" diff --git a/adapters/ae.h b/adapters/ae.h index 9923f1b..44db8ee 100644 --- a/adapters/ae.h +++ b/adapters/ae.h @@ -13,7 +13,7 @@ #define __HIREDIS_AE_H__ #include #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" typedef struct redisAeEvents { diff --git a/adapters/glib.h b/adapters/glib.h index 3b6772c..f3143ed 100644 --- a/adapters/glib.h +++ b/adapters/glib.h @@ -14,7 +14,7 @@ #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" typedef struct diff --git a/adapters/ivykis.h b/adapters/ivykis.h index 3de8d0c..544723d 100644 --- a/adapters/ivykis.h +++ b/adapters/ivykis.h @@ -12,7 +12,7 @@ #ifndef __HIREDIS_IVYKIS_H__ #define __HIREDIS_IVYKIS_H__ #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" typedef struct redisIvykisEvents { diff --git a/adapters/libev.h b/adapters/libev.h index ad8e79c..265e642 100644 --- a/adapters/libev.h +++ b/adapters/libev.h @@ -16,7 +16,7 @@ #include #include #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" typedef struct redisLibevEvents { diff --git a/adapters/libevent.h b/adapters/libevent.h index c7cc4e7..936c37e 100644 --- a/adapters/libevent.h +++ b/adapters/libevent.h @@ -12,7 +12,7 @@ #ifndef __HIREDIS_LIBEVENT_H__ #define __HIREDIS_LIBEVENT_H__ #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" #define REDIS_LIBEVENT_DELETED 0x01 diff --git a/adapters/libhv.h b/adapters/libhv.h index 3dd6978..4955bb4 100644 --- a/adapters/libhv.h +++ b/adapters/libhv.h @@ -13,7 +13,7 @@ #define __HIREDIS_LIBHV_H__ #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" typedef struct redisLibhvEvents { diff --git a/adapters/libsdevent.h b/adapters/libsdevent.h index 74364a5..dc4249a 100644 --- a/adapters/libsdevent.h +++ b/adapters/libsdevent.h @@ -12,7 +12,7 @@ #ifndef HIREDIS_LIBSDEVENT_H #define HIREDIS_LIBSDEVENT_H #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" #define REDIS_LIBSDEVENT_DELETED 0x01 diff --git a/adapters/libuv.h b/adapters/libuv.h index 85e12ed..317d5e1 100644 --- a/adapters/libuv.h +++ b/adapters/libuv.h @@ -13,7 +13,7 @@ #define __HIREDIS_LIBUV_H__ #include #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" #include diff --git a/adapters/macosx.h b/adapters/macosx.h index fafd43b..7ae5e5a 100644 --- a/adapters/macosx.h +++ b/adapters/macosx.h @@ -14,7 +14,7 @@ #include -#include "../hiredis.h" +#include "../hiredict.h" #include "../async.h" typedef struct { diff --git a/adapters/redismoduleapi.h b/adapters/redismoduleapi.h index 4614b8d..b9bf922 100644 --- a/adapters/redismoduleapi.h +++ b/adapters/redismoduleapi.h @@ -15,7 +15,7 @@ #include "redismodule.h" #include "../async.h" -#include "../hiredis.h" +#include "../hiredict.h" #include diff --git a/async.h b/async.h index f702d86..3244a98 100644 --- a/async.h +++ b/async.h @@ -13,7 +13,7 @@ #ifndef __HIREDIS_ASYNC_H #define __HIREDIS_ASYNC_H -#include "hiredis.h" +#include "hiredict.h" #ifdef __cplusplus extern "C" { diff --git a/examples/example-ae.c b/examples/example-ae.c index 838a967..983ca9c 100644 --- a/examples/example-ae.c +++ b/examples/example-ae.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-glib.c b/examples/example-glib.c index eea9acc..46aa550 100644 --- a/examples/example-glib.c +++ b/examples/example-glib.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include diff --git a/examples/example-ivykis.c b/examples/example-ivykis.c index a581e02..989fa12 100644 --- a/examples/example-ivykis.c +++ b/examples/example-ivykis.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-libev.c b/examples/example-libev.c index cc6d27f..ade7ed1 100644 --- a/examples/example-libev.c +++ b/examples/example-libev.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-libevent-ssl.c b/examples/example-libevent-ssl.c index 99f8ebf..b2c6b56 100644 --- a/examples/example-libevent-ssl.c +++ b/examples/example-libevent-ssl.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/examples/example-libevent.c b/examples/example-libevent.c index d0d3c79..747f343 100644 --- a/examples/example-libevent.c +++ b/examples/example-libevent.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-libhv.c b/examples/example-libhv.c index a69f236..4878039 100644 --- a/examples/example-libhv.c +++ b/examples/example-libhv.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-libsdevent.c b/examples/example-libsdevent.c index adc54f9..8599b76 100644 --- a/examples/example-libsdevent.c +++ b/examples/example-libsdevent.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-libuv.c b/examples/example-libuv.c index b92a29f..7d0e624 100644 --- a/examples/example-libuv.c +++ b/examples/example-libuv.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-macosx.c b/examples/example-macosx.c index 9e85627..659d3b5 100644 --- a/examples/example-macosx.c +++ b/examples/example-macosx.c @@ -8,7 +8,7 @@ #include -#include +#include #include #include diff --git a/examples/example-push.c b/examples/example-push.c index 2003bad..a00422f 100644 --- a/examples/example-push.c +++ b/examples/example-push.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #define KEY_COUNT 5 diff --git a/examples/example-redismoduleapi.c b/examples/example-redismoduleapi.c index 3bbbbc5..37bba9c 100644 --- a/examples/example-redismoduleapi.c +++ b/examples/example-redismoduleapi.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/examples/example-ssl.c b/examples/example-ssl.c index 03cf556..1654f5d 100644 --- a/examples/example-ssl.c +++ b/examples/example-ssl.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #ifdef _MSC_VER diff --git a/examples/example.c b/examples/example.c index e2c1842..a87e5cf 100644 --- a/examples/example.c +++ b/examples/example.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #ifdef _MSC_VER #include /* For struct timeval */ diff --git a/fuzzing/format_command_fuzzer.c b/fuzzing/format_command_fuzzer.c index 65d8b91..99fde7b 100644 --- a/fuzzing/format_command_fuzzer.c +++ b/fuzzing/format_command_fuzzer.c @@ -17,7 +17,7 @@ #include #include -#include "hiredis.h" +#include "hiredict.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *new_str, *cmd; diff --git a/hiredict-config.cmake.in b/hiredict-config.cmake.in new file mode 100644 index 0000000..0339858 --- /dev/null +++ b/hiredict-config.cmake.in @@ -0,0 +1,13 @@ +@PACKAGE_INIT@ + +set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@") + +IF (NOT TARGET hiredis::@hiredis_export_name@) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake) +ENDIF() + +SET(hiredis_LIBRARIES hiredis::@hiredis_export_name@) +SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR}) + +check_required_components(hiredis) + diff --git a/hiredict.c b/hiredict.c new file mode 100644 index 0000000..1686abf --- /dev/null +++ b/hiredict.c @@ -0,0 +1,1210 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * SPDX-FileCopyrightText: 2024 Hiredict Contributors + * SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo + * SPDX-FileCopyrightText: 2024 Pieter Noordhuis + * SPDX-FileCopyrightText: 2024 Matt Stancliff + * SPDX-FileCopyrightText: 2024 Jan-Erik Rediger + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: LGPL-3.0-or-later + * + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include + +#include "hiredict.h" +#include "net.h" +#include "sds.h" +#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 = { + .close = redisNetClose, + .free_privctx = NULL, + .async_read = redisAsyncRead, + .async_write = redisAsyncWrite, + .read = redisNetRead, + .write = redisNetWrite +}; + +static redisReply *createReplyObject(int type); +static void *createStringObject(const redisReadTask *task, char *str, size_t len); +static void *createArrayObject(const redisReadTask *task, size_t elements); +static void *createIntegerObject(const redisReadTask *task, long long value); +static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len); +static void *createNilObject(const redisReadTask *task); +static void *createBoolObject(const redisReadTask *task, int bval); + +/* Default set of functions to build the reply. Keep in mind that such a + * function returning NULL is interpreted as OOM. */ +static redisReplyObjectFunctions defaultFunctions = { + createStringObject, + createArrayObject, + createIntegerObject, + createDoubleObject, + createNilObject, + createBoolObject, + freeReplyObject +}; + +/* Create a reply object */ +static redisReply *createReplyObject(int type) { + redisReply *r = hi_calloc(1,sizeof(*r)); + + if (r == NULL) + return NULL; + + r->type = type; + return r; +} + +/* Free a reply object */ +void freeReplyObject(void *reply) { + redisReply *r = reply; + size_t j; + + if (r == NULL) + return; + + switch(r->type) { + case REDIS_REPLY_INTEGER: + case REDIS_REPLY_NIL: + case REDIS_REPLY_BOOL: + break; /* Nothing to free */ + case REDIS_REPLY_ARRAY: + case REDIS_REPLY_MAP: + case REDIS_REPLY_ATTR: + case REDIS_REPLY_SET: + case REDIS_REPLY_PUSH: + if (r->element != NULL) { + for (j = 0; j < r->elements; j++) + freeReplyObject(r->element[j]); + hi_free(r->element); + } + break; + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_STRING: + case REDIS_REPLY_DOUBLE: + case REDIS_REPLY_VERB: + case REDIS_REPLY_BIGNUM: + hi_free(r->str); + break; + } + hi_free(r); +} + +static void *createStringObject(const redisReadTask *task, char *str, size_t len) { + redisReply *r, *parent; + char *buf; + + r = createReplyObject(task->type); + if (r == NULL) + return NULL; + + assert(task->type == REDIS_REPLY_ERROR || + task->type == REDIS_REPLY_STATUS || + task->type == REDIS_REPLY_STRING || + task->type == REDIS_REPLY_VERB || + task->type == REDIS_REPLY_BIGNUM); + + /* Copy string value */ + if (task->type == REDIS_REPLY_VERB) { + buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */ + if (buf == NULL) goto oom; + + memcpy(r->vtype,str,3); + r->vtype[3] = '\0'; + memcpy(buf,str+4,len-4); + buf[len-4] = '\0'; + r->len = len - 4; + } else { + buf = hi_malloc(len+1); + if (buf == NULL) goto oom; + + memcpy(buf,str,len); + buf[len] = '\0'; + r->len = len; + } + r->str = buf; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY || + parent->type == REDIS_REPLY_MAP || + parent->type == REDIS_REPLY_ATTR || + parent->type == REDIS_REPLY_SET || + parent->type == REDIS_REPLY_PUSH); + parent->element[task->idx] = r; + } + return r; + +oom: + freeReplyObject(r); + return NULL; +} + +static void *createArrayObject(const redisReadTask *task, size_t elements) { + redisReply *r, *parent; + + r = createReplyObject(task->type); + if (r == NULL) + return NULL; + + if (elements > 0) { + r->element = hi_calloc(elements,sizeof(redisReply*)); + if (r->element == NULL) { + freeReplyObject(r); + return NULL; + } + } + + r->elements = elements; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY || + parent->type == REDIS_REPLY_MAP || + parent->type == REDIS_REPLY_ATTR || + parent->type == REDIS_REPLY_SET || + parent->type == REDIS_REPLY_PUSH); + parent->element[task->idx] = r; + } + return r; +} + +static void *createIntegerObject(const redisReadTask *task, long long value) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_INTEGER); + if (r == NULL) + return NULL; + + r->integer = value; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY || + parent->type == REDIS_REPLY_MAP || + parent->type == REDIS_REPLY_ATTR || + parent->type == REDIS_REPLY_SET || + parent->type == REDIS_REPLY_PUSH); + parent->element[task->idx] = r; + } + return r; +} + +static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) { + redisReply *r, *parent; + + if (len == SIZE_MAX) // Prevents hi_malloc(0) if len equals to SIZE_MAX + return NULL; + + r = createReplyObject(REDIS_REPLY_DOUBLE); + if (r == NULL) + return NULL; + + r->dval = value; + r->str = hi_malloc(len+1); + if (r->str == NULL) { + freeReplyObject(r); + return NULL; + } + + /* The double reply also has the original protocol string representing a + * double as a null terminated string. This way the caller does not need + * to format back for string conversion, especially since Redis does efforts + * to make the string more human readable avoiding the calssical double + * decimal string conversion artifacts. */ + memcpy(r->str, str, len); + r->str[len] = '\0'; + r->len = len; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY || + parent->type == REDIS_REPLY_MAP || + parent->type == REDIS_REPLY_ATTR || + parent->type == REDIS_REPLY_SET || + parent->type == REDIS_REPLY_PUSH); + parent->element[task->idx] = r; + } + return r; +} + +static void *createNilObject(const redisReadTask *task) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_NIL); + if (r == NULL) + return NULL; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY || + parent->type == REDIS_REPLY_MAP || + parent->type == REDIS_REPLY_ATTR || + parent->type == REDIS_REPLY_SET || + parent->type == REDIS_REPLY_PUSH); + parent->element[task->idx] = r; + } + return r; +} + +static void *createBoolObject(const redisReadTask *task, int bval) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_BOOL); + if (r == NULL) + return NULL; + + r->integer = bval != 0; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY || + parent->type == REDIS_REPLY_MAP || + parent->type == REDIS_REPLY_ATTR || + parent->type == REDIS_REPLY_SET || + parent->type == REDIS_REPLY_PUSH); + parent->element[task->idx] = r; + } + return r; +} + +/* Return the number of digits of 'v' when converted to string in radix 10. + * Implementation borrowed from link in redis/src/util.c:string2ll(). */ +static uint32_t countDigits(uint64_t v) { + uint32_t result = 1; + for (;;) { + if (v < 10) return result; + if (v < 100) return result + 1; + if (v < 1000) return result + 2; + if (v < 10000) return result + 3; + v /= 10000U; + result += 4; + } +} + +/* Helper that calculates the bulk length given a certain string length. */ +static size_t bulklen(size_t len) { + return 1+countDigits(len)+2+len+2; +} + +int redisvFormatCommand(char **target, const char *format, va_list ap) { + const char *c = format; + char *cmd = NULL; /* final command */ + int pos; /* position in final command */ + sds curarg, newarg; /* current argument */ + int touched = 0; /* was the current argument touched? */ + char **curargv = NULL, **newargv = NULL; + int argc = 0; + int totlen = 0; + int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */ + int j; + + /* Abort if there is not target to set */ + if (target == NULL) + return -1; + + /* Build the command string accordingly to protocol */ + curarg = sdsempty(); + if (curarg == NULL) + return -1; + + while(*c != '\0') { + if (*c != '%' || c[1] == '\0') { + if (*c == ' ') { + if (touched) { + newargv = hi_realloc(curargv,sizeof(char*)*(argc+1)); + if (newargv == NULL) goto memory_err; + curargv = newargv; + curargv[argc++] = curarg; + totlen += bulklen(sdslen(curarg)); + + /* curarg is put in argv so it can be overwritten. */ + curarg = sdsempty(); + if (curarg == NULL) goto memory_err; + touched = 0; + } + } else { + newarg = sdscatlen(curarg,c,1); + if (newarg == NULL) goto memory_err; + curarg = newarg; + touched = 1; + } + } else { + char *arg; + size_t size; + + /* Set newarg so it can be checked even if it is not touched. */ + newarg = curarg; + + switch(c[1]) { + case 's': + arg = va_arg(ap,char*); + size = strlen(arg); + if (size > 0) + newarg = sdscatlen(curarg,arg,size); + break; + case 'b': + arg = va_arg(ap,char*); + size = va_arg(ap,size_t); + if (size > 0) + newarg = sdscatlen(curarg,arg,size); + break; + case '%': + newarg = sdscat(curarg,"%"); + break; + default: + /* Try to detect printf format */ + { + static const char intfmts[] = "diouxX"; + static const char flags[] = "#0-+ "; + char _format[16]; + const char *_p = c+1; + size_t _l = 0; + va_list _cpy; + + /* Flags */ + while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; + + /* Field width */ + while (*_p != '\0' && isdigit((int) *_p)) _p++; + + /* Precision */ + if (*_p == '.') { + _p++; + while (*_p != '\0' && isdigit((int) *_p)) _p++; + } + + /* Copy va_list before consuming with va_arg */ + va_copy(_cpy,ap); + + /* Make sure we have more characters otherwise strchr() accepts + * '\0' as an integer specifier. This is checked after above + * va_copy() to avoid UB in fmt_invalid's call to va_end(). */ + if (*_p == '\0') goto fmt_invalid; + + /* Integer conversion (without modifiers) */ + if (strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); + goto fmt_valid; + } + + /* Double conversion (without modifiers) */ + if (strchr("eEfFgGaA",*_p) != NULL) { + va_arg(ap,double); + goto fmt_valid; + } + + /* Size: char */ + if (_p[0] == 'h' && _p[1] == 'h') { + _p += 2; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); /* char gets promoted to int */ + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: short */ + if (_p[0] == 'h') { + _p += 1; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); /* short gets promoted to int */ + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: long long */ + if (_p[0] == 'l' && _p[1] == 'l') { + _p += 2; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,long long); + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: long */ + if (_p[0] == 'l') { + _p += 1; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,long); + goto fmt_valid; + } + goto fmt_invalid; + } + + fmt_invalid: + va_end(_cpy); + goto format_err; + + fmt_valid: + _l = (_p+1)-c; + if (_l < sizeof(_format)-2) { + memcpy(_format,c,_l); + _format[_l] = '\0'; + newarg = sdscatvprintf(curarg,_format,_cpy); + + /* Update current position (note: outer blocks + * increment c twice so compensate here) */ + c = _p-1; + } + + va_end(_cpy); + break; + } + } + + if (newarg == NULL) goto memory_err; + curarg = newarg; + + touched = 1; + c++; + if (*c == '\0') + break; + } + c++; + } + + /* Add the last argument if needed */ + if (touched) { + newargv = hi_realloc(curargv,sizeof(char*)*(argc+1)); + if (newargv == NULL) goto memory_err; + curargv = newargv; + curargv[argc++] = curarg; + totlen += bulklen(sdslen(curarg)); + } else { + sdsfree(curarg); + } + + /* Clear curarg because it was put in curargv or was free'd. */ + curarg = NULL; + + /* Add bytes needed to hold multi bulk count */ + totlen += 1+countDigits(argc)+2; + + /* Build the command at protocol level */ + cmd = hi_malloc(totlen+1); + if (cmd == NULL) goto memory_err; + + pos = sprintf(cmd,"*%d\r\n",argc); + for (j = 0; j < argc; j++) { + pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); + memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); + pos += sdslen(curargv[j]); + sdsfree(curargv[j]); + cmd[pos++] = '\r'; + cmd[pos++] = '\n'; + } + assert(pos == totlen); + cmd[pos] = '\0'; + + hi_free(curargv); + *target = cmd; + return totlen; + +format_err: + error_type = -2; + goto cleanup; + +memory_err: + error_type = -1; + goto cleanup; + +cleanup: + if (curargv) { + while(argc--) + sdsfree(curargv[argc]); + hi_free(curargv); + } + + sdsfree(curarg); + hi_free(cmd); + + return error_type; +} + +/* Format a command according to the Redis protocol. This function + * takes a format similar to printf: + * + * %s represents a C null terminated string you want to interpolate + * %b represents a binary safe string + * + * When using %b you need to provide both the pointer to the string + * and the length in bytes as a size_t. Examples: + * + * len = redisFormatCommand(target, "GET %s", mykey); + * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen); + */ +int redisFormatCommand(char **target, const char *format, ...) { + va_list ap; + int len; + va_start(ap,format); + len = redisvFormatCommand(target,format,ap); + va_end(ap); + + /* The API says "-1" means bad result, but we now also return "-2" in some + * cases. Force the return value to always be -1. */ + if (len < 0) + len = -1; + + return len; +} + +/* Format a command according to the Redis protocol using an sds string and + * sdscatfmt for the processing of arguments. This function takes the + * number of arguments, an array with arguments and an array with their + * lengths. If the latter is set to NULL, strlen will be used to compute the + * argument lengths. + */ +long long redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, + const size_t *argvlen) +{ + sds cmd, aux; + unsigned long long totlen, len; + int j; + + /* Abort on a NULL target */ + if (target == NULL) + return -1; + + /* Calculate our total size */ + totlen = 1+countDigits(argc)+2; + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + totlen += bulklen(len); + } + + /* Use an SDS string for command construction */ + cmd = sdsempty(); + if (cmd == NULL) + return -1; + + /* We already know how much storage we need */ + aux = sdsMakeRoomFor(cmd, totlen); + if (aux == NULL) { + sdsfree(cmd); + return -1; + } + + cmd = aux; + + /* Construct command */ + cmd = sdscatfmt(cmd, "*%i\r\n", argc); + for (j=0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + cmd = sdscatfmt(cmd, "$%U\r\n", len); + cmd = sdscatlen(cmd, argv[j], len); + cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); + } + + assert(sdslen(cmd)==totlen); + + *target = cmd; + return totlen; +} + +void redisFreeSdsCommand(sds cmd) { + sdsfree(cmd); +} + +/* Format a command according to the Redis protocol. This function takes the + * number of arguments, an array with arguments and an array with their + * lengths. If the latter is set to NULL, strlen will be used to compute the + * argument lengths. + */ +long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) { + char *cmd = NULL; /* final command */ + size_t pos; /* position in final command */ + size_t len, totlen; + int j; + + /* Abort on a NULL target */ + if (target == NULL) + return -1; + + /* Calculate number of bytes needed for the command */ + totlen = 1+countDigits(argc)+2; + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + totlen += bulklen(len); + } + + /* Build the command at protocol level */ + cmd = hi_malloc(totlen+1); + if (cmd == NULL) + return -1; + + pos = sprintf(cmd,"*%d\r\n",argc); + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + pos += sprintf(cmd+pos,"$%zu\r\n",len); + memcpy(cmd+pos,argv[j],len); + pos += len; + cmd[pos++] = '\r'; + cmd[pos++] = '\n'; + } + assert(pos == totlen); + cmd[pos] = '\0'; + + *target = cmd; + return totlen; +} + +void redisFreeCommand(char *cmd) { + hi_free(cmd); +} + +void __redisSetError(redisContext *c, int type, const char *str) { + size_t len; + + c->err = type; + if (str != NULL) { + len = strlen(str); + len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1); + memcpy(c->errstr,str,len); + c->errstr[len] = '\0'; + } else { + /* Only REDIS_ERR_IO may lack a description! */ + assert(type == REDIS_ERR_IO); + strerror_r(errno, c->errstr, sizeof(c->errstr)); + } +} + +redisReader *redisReaderCreate(void) { + return redisReaderCreateWithFunctions(&defaultFunctions); +} + +static void redisPushAutoFree(void *privdata, void *reply) { + (void)privdata; + freeReplyObject(reply); +} + +static redisContext *redisContextInit(void) { + redisContext *c; + + c = hi_calloc(1, sizeof(*c)); + if (c == NULL) + return NULL; + + c->funcs = &redisContextDefaultFuncs; + + c->obuf = sdsempty(); + c->reader = redisReaderCreate(); + c->fd = REDIS_INVALID_FD; + + if (c->obuf == NULL || c->reader == NULL) { + redisFree(c); + return NULL; + } + + return c; +} + +void redisFree(redisContext *c) { + if (c == NULL) + return; + + if (c->funcs && c->funcs->close) { + c->funcs->close(c); + } + + sdsfree(c->obuf); + redisReaderFree(c->reader); + hi_free(c->tcp.host); + hi_free(c->tcp.source_addr); + hi_free(c->unix_sock.path); + hi_free(c->connect_timeout); + hi_free(c->command_timeout); + hi_free(c->saddr); + + if (c->privdata && c->free_privdata) + c->free_privdata(c->privdata); + + if (c->funcs && c->funcs->free_privctx) + c->funcs->free_privctx(c->privctx); + + memset(c, 0xff, sizeof(*c)); + hi_free(c); +} + +redisFD redisFreeKeepFd(redisContext *c) { + redisFD fd = c->fd; + c->fd = REDIS_INVALID_FD; + redisFree(c); + return fd; +} + +int redisReconnect(redisContext *c) { + c->err = 0; + memset(c->errstr, '\0', strlen(c->errstr)); + + if (c->privctx && c->funcs->free_privctx) { + c->funcs->free_privctx(c->privctx); + c->privctx = NULL; + } + + if (c->funcs && c->funcs->close) { + c->funcs->close(c); + } + + sdsfree(c->obuf); + redisReaderFree(c->reader); + + c->obuf = sdsempty(); + c->reader = redisReaderCreate(); + + if (c->obuf == NULL || c->reader == NULL) { + __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; + } + + int ret = REDIS_ERR; + if (c->connection_type == REDIS_CONN_TCP) { + ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, + c->connect_timeout, c->tcp.source_addr); + } else if (c->connection_type == REDIS_CONN_UNIX) { + 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; + } + + 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(); + if (c == NULL) { + return NULL; + } + if (!(options->options & REDIS_OPT_NONBLOCK)) { + c->flags |= REDIS_BLOCK; + } + if (options->options & REDIS_OPT_REUSEADDR) { + c->flags |= REDIS_REUSEADDR; + } + if (options->options & REDIS_OPT_NOAUTOFREE) { + c->flags |= REDIS_NO_AUTO_FREE; + } + if (options->options & REDIS_OPT_NOAUTOFREEREPLIES) { + c->flags |= REDIS_NO_AUTO_FREE_REPLIES; + } + if (options->options & REDIS_OPT_PREFER_IPV4) { + c->flags |= REDIS_PREFER_IPV4; + } + if (options->options & REDIS_OPT_PREFER_IPV6) { + c->flags |= REDIS_PREFER_IPV6; + } + + /* 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->connect_timeout, + options->endpoint.tcp.source_addr); + } else if (options->type == REDIS_CONN_UNIX) { + redisContextConnectUnix(c, options->endpoint.unix_socket, + options->connect_timeout); + } else if (options->type == REDIS_CONN_USERFD) { + c->fd = options->endpoint.fd; + c->flags |= REDIS_CONNECTED; + } else { + redisFree(c); + return NULL; + } + + if (c->err == 0 && c->fd != REDIS_INVALID_FD && + options->command_timeout != NULL && (c->flags & REDIS_BLOCK)) + { + redisContextSetTimeout(c, *options->command_timeout); + } + + return c; +} + +/* Connect to a Redis instance. On error the field error in the returned + * context will be set to the return value of the error function. + * When no set of reply functions is given, the default set will be used. */ +redisContext *redisConnect(const char *ip, int port) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_TCP(&options, ip, port); + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_TCP(&options, ip, port); + options.connect_timeout = &tv; + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectNonBlock(const char *ip, int port) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_TCP(&options, ip, port); + options.options |= REDIS_OPT_NONBLOCK; + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_TCP(&options, ip, port); + options.endpoint.tcp.source_addr = source_addr; + options.options |= REDIS_OPT_NONBLOCK; + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_TCP(&options, ip, port); + options.endpoint.tcp.source_addr = source_addr; + options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR; + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectUnix(const char *path) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_UNIX(&options, path); + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_UNIX(&options, path); + options.connect_timeout = &tv; + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectUnixNonBlock(const char *path) { + redisOptions options = {0}; + REDIS_OPTIONS_SET_UNIX(&options, path); + options.options |= REDIS_OPT_NONBLOCK; + return redisConnectWithOptions(&options); +} + +redisContext *redisConnectFd(redisFD fd) { + redisOptions options = {0}; + options.type = REDIS_CONN_USERFD; + options.endpoint.fd = fd; + return redisConnectWithOptions(&options); +} + +/* Set read/write timeout on a blocking socket. */ +int redisSetTimeout(redisContext *c, const struct timeval tv) { + if (c->flags & REDIS_BLOCK) + return redisContextSetTimeout(c,tv); + return REDIS_ERR; +} + +int redisEnableKeepAliveWithInterval(redisContext *c, int interval) { + return redisKeepAlive(c, interval); +} + +/* Enable connection KeepAlive. */ +int redisEnableKeepAlive(redisContext *c) { + 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. */ +redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) { + redisPushFn *old = c->push_cb; + c->push_cb = fn; + return old; +} + +/* Use this function to handle a read event on the descriptor. It will try + * and read some bytes from the socket and feed them to the reply parser. + * + * After this function is called, you may use redisGetReplyFromReader to + * see if there is a reply available. */ +int redisBufferRead(redisContext *c) { + char buf[1024*16]; + int nread; + + /* Return early when the context has seen an error. */ + if (c->err) + return REDIS_ERR; + + nread = c->funcs->read(c, buf, sizeof(buf)); + if (nread < 0) { + return REDIS_ERR; + } + if (nread > 0 && redisReaderFeed(c->reader, buf, nread) != REDIS_OK) { + __redisSetError(c, c->reader->err, c->reader->errstr); + return REDIS_ERR; + } + return REDIS_OK; +} + +/* Write the output buffer to the socket. + * + * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was + * successfully written to the socket. When the buffer is empty after the + * write operation, "done" is set to 1 (if given). + * + * Returns REDIS_ERR if an unrecoverable error occurred in the underlying + * c->funcs->write function. + */ +int redisBufferWrite(redisContext *c, int *done) { + + /* Return early when the context has seen an error. */ + if (c->err) + return REDIS_ERR; + + if (sdslen(c->obuf) > 0) { + ssize_t nwritten = c->funcs->write(c); + if (nwritten < 0) { + return REDIS_ERR; + } else if (nwritten > 0) { + if (nwritten == (ssize_t)sdslen(c->obuf)) { + sdsfree(c->obuf); + c->obuf = sdsempty(); + if (c->obuf == NULL) + goto oom; + } else { + if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom; + } + } + } + if (done != NULL) *done = (sdslen(c->obuf) == 0); + return REDIS_OK; + +oom: + __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); + return REDIS_ERR; +} + +/* Internal helper that returns 1 if the reply was a RESP3 PUSH + * message and we handled it with a user-provided callback. */ +static int redisHandledPushReply(redisContext *c, void *reply) { + if (reply && c->push_cb && redisIsPushReply(reply)) { + c->push_cb(c->privdata, reply); + return 1; + } + + return 0; +} + +/* Get a reply from our reader or set an error in the context. */ +int redisGetReplyFromReader(redisContext *c, void **reply) { + if (redisReaderGetReply(c->reader, reply) == REDIS_ERR) { + __redisSetError(c,c->reader->err,c->reader->errstr); + return REDIS_ERR; + } + + return REDIS_OK; +} + +/* Internal helper to get the next reply from our reader while handling + * any PUSH messages we encounter along the way. This is separate from + * redisGetReplyFromReader so as to not change its behavior. */ +static int redisNextInBandReplyFromReader(redisContext *c, void **reply) { + do { + if (redisGetReplyFromReader(c, reply) == REDIS_ERR) + return REDIS_ERR; + } while (redisHandledPushReply(c, *reply)); + + return REDIS_OK; +} + +int redisGetReply(redisContext *c, void **reply) { + int wdone = 0; + void *aux = NULL; + + /* Try to read pending replies */ + if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR) + return REDIS_ERR; + + /* For the blocking context, flush output buffer and read reply */ + if (aux == NULL && c->flags & REDIS_BLOCK) { + /* Write until done */ + do { + if (redisBufferWrite(c,&wdone) == REDIS_ERR) + return REDIS_ERR; + } while (!wdone); + + /* Read until there is a reply */ + do { + if (redisBufferRead(c) == REDIS_ERR) + return REDIS_ERR; + + if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR) + return REDIS_ERR; + } while (aux == NULL); + } + + /* Set reply or free it if we were passed NULL */ + if (reply != NULL) { + *reply = aux; + } else { + freeReplyObject(aux); + } + + return REDIS_OK; +} + + +/* Helper function for the redisAppendCommand* family of functions. + * + * Write a formatted command to the output buffer. When this family + * is used, you need to call redisGetReply yourself to retrieve + * the reply (or replies in pub/sub). + */ +int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) { + sds newbuf; + + newbuf = sdscatlen(c->obuf,cmd,len); + if (newbuf == NULL) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + c->obuf = newbuf; + return REDIS_OK; +} + +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) { + + if (__redisAppendCommand(c, cmd, len) != REDIS_OK) { + return REDIS_ERR; + } + + return REDIS_OK; +} + +int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { + char *cmd; + int len; + + len = redisvFormatCommand(&cmd,format,ap); + if (len == -1) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } else if (len == -2) { + __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string"); + return REDIS_ERR; + } + + if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { + hi_free(cmd); + return REDIS_ERR; + } + + hi_free(cmd); + return REDIS_OK; +} + +int redisAppendCommand(redisContext *c, const char *format, ...) { + va_list ap; + int ret; + + va_start(ap,format); + ret = redisvAppendCommand(c,format,ap); + va_end(ap); + return ret; +} + +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { + sds cmd; + long long len; + + len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); + if (len == -1) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { + sdsfree(cmd); + return REDIS_ERR; + } + + sdsfree(cmd); + return REDIS_OK; +} + +/* Helper function for the redisCommand* family of functions. + * + * Write a formatted command to the output buffer. If the given context is + * blocking, immediately read the reply into the "reply" pointer. When the + * context is non-blocking, the "reply" pointer will not be used and the + * command is simply appended to the write buffer. + * + * Returns the reply when a reply was successfully retrieved. Returns NULL + * otherwise. When NULL is returned in a blocking context, the error field + * in the context will be set. + */ +static void *__redisBlockForReply(redisContext *c) { + void *reply; + + if (c->flags & REDIS_BLOCK) { + if (redisGetReply(c,&reply) != REDIS_OK) + return NULL; + return reply; + } + return NULL; +} + +void *redisvCommand(redisContext *c, const char *format, va_list ap) { + if (redisvAppendCommand(c,format,ap) != REDIS_OK) + return NULL; + return __redisBlockForReply(c); +} + +void *redisCommand(redisContext *c, const char *format, ...) { + va_list ap; + va_start(ap,format); + void *reply = redisvCommand(c,format,ap); + va_end(ap); + return reply; +} + +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { + if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK) + return NULL; + return __redisBlockForReply(c); +} diff --git a/hiredict.h b/hiredict.h new file mode 100644 index 0000000..1936b4d --- /dev/null +++ b/hiredict.h @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * SPDX-FileCopyrightText: 2024 Hiredict Contributors + * SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo + * SPDX-FileCopyrightText: 2024 Pieter Noordhuis + * SPDX-FileCopyrightText: 2024 Matt Stancliff + * SPDX-FileCopyrightText: 2024 Jan-Erik Rediger + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: LGPL-3.0-or-later + * + */ + +#ifndef __HIREDIS_H +#define __HIREDIS_H +#include "read.h" +#include /* for va_list */ +#ifndef _MSC_VER +#include /* for struct timeval */ +#else +struct timeval; /* forward declaration */ +typedef long long ssize_t; +#endif +#include /* uintXX_t, etc */ +#include "sds.h" /* for sds */ +#include "alloc.h" /* for allocation wrappers */ + +#define HIREDIS_MAJOR 1 +#define HIREDIS_MINOR 2 +#define HIREDIS_PATCH 0 +#define HIREDIS_SONAME 1.2.1-dev + +/* Connection type can be blocking or non-blocking and is set in the + * least significant bit of the flags field in redisContext. */ +#define REDIS_BLOCK 0x1 + +/* Connection may be disconnected before being free'd. The second bit + * in the flags field is set when the context is connected. */ +#define REDIS_CONNECTED 0x2 + +/* The async API might try to disconnect cleanly and flush the output + * buffer and read all subsequent replies before disconnecting. + * This flag means no new commands can come in and the connection + * should be terminated once all replies have been read. */ +#define REDIS_DISCONNECTING 0x4 + +/* Flag specific to the async API which means that the context should be clean + * up as soon as possible. */ +#define REDIS_FREEING 0x8 + +/* Flag that is set when an async callback is executed. */ +#define REDIS_IN_CALLBACK 0x10 + +/* Flag that is set when the async context has one or more subscriptions. */ +#define REDIS_SUBSCRIBED 0x20 + +/* Flag that is set when monitor mode is active */ +#define REDIS_MONITORING 0x40 + +/* Flag that is set when we should set SO_REUSEADDR before calling bind() */ +#define REDIS_REUSEADDR 0x80 + +/* Flag that is set when the async connection supports push replies. */ +#define REDIS_SUPPORTS_PUSH 0x100 + +/** + * Flag that indicates the user does not want the context to + * be automatically freed upon error + */ +#define REDIS_NO_AUTO_FREE 0x200 + +/* Flag that indicates the user does not want replies to be automatically freed */ +#define REDIS_NO_AUTO_FREE_REPLIES 0x400 + +/* Flags to prefer IPv6 or IPv4 when doing DNS lookup. (If both are set, + * AF_UNSPEC is used.) */ +#define REDIS_PREFER_IPV4 0x800 +#define REDIS_PREFER_IPV6 0x1000 + +#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ + +/* number of times we retry to connect in the case of EADDRNOTAVAIL and + * SO_REUSEADDR is being used. */ +#define REDIS_CONNECT_RETRIES 10 + +/* Forward declarations for structs defined elsewhere */ +struct redisAsyncContext; +struct redisContext; + +/* RESP3 push helpers and callback prototypes */ +#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH) +typedef void (redisPushFn)(void *, void *); +typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *); + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the reply object returned by redisCommand() */ +typedef struct redisReply { + int type; /* REDIS_REPLY_* */ + long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ + double dval; /* The double when type is REDIS_REPLY_DOUBLE */ + size_t len; /* Length of string */ + char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING + REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval), + and REDIS_REPLY_BIGNUM. */ + char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null + terminated 3 character content type, such as "txt". */ + size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ + struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ +} redisReply; + +redisReader *redisReaderCreate(void); + +/* Function to free the reply objects hiredis returns by default. */ +void freeReplyObject(void *reply); + +/* Functions to format a command according to the protocol. */ +int redisvFormatCommand(char **target, const char *format, va_list ap); +int redisFormatCommand(char **target, const char *format, ...); +long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); +long long redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); +void redisFreeCommand(char *cmd); +void redisFreeSdsCommand(sds cmd); + +enum redisConnectionType { + REDIS_CONN_TCP, + REDIS_CONN_UNIX, + REDIS_CONN_USERFD +}; + +struct redisSsl; + +#define REDIS_OPT_NONBLOCK 0x01 +#define REDIS_OPT_REUSEADDR 0x02 +#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) + +/* In Unix systems a file descriptor is a regular signed int, with -1 + * representing an invalid descriptor. In Windows it is a SOCKET + * (32- or 64-bit unsigned integer depending on the architecture), where + * all bits set (~0) is INVALID_SOCKET. */ +#ifndef _WIN32 +typedef int redisFD; +#define REDIS_INVALID_FD -1 +#else +#ifdef _WIN64 +typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */ +#else +typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */ +#endif +#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */ +#endif + +typedef struct { + /* + * the type of connection to use. This also indicates which + * `endpoint` member field to use + */ + int type; + /* bit field of REDIS_OPT_xxx */ + int options; + /* timeout value for connect operation. If NULL, no timeout is used */ + const struct timeval *connect_timeout; + /* timeout value for commands. If NULL, no timeout is used. This can be + * updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */ + const struct timeval *command_timeout; + union { + /** use this field for tcp/ip connections */ + struct { + const char *source_addr; + const char *ip; + int port; + } tcp; + /** use this field for unix domain sockets */ + const char *unix_socket; + /** + * use this field to have hiredis operate an already-open + * file descriptor */ + redisFD fd; + } endpoint; + + /* Optional user defined data/destructor */ + void *privdata; + void (*free_privdata)(void *); + + /* A user defined PUSH message callback */ + redisPushFn *push_cb; + redisAsyncPushFn *async_push_cb; +} redisOptions; + +/** + * Helper macros to initialize options to their specified fields. + */ +#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) do { \ + (opts)->type = REDIS_CONN_TCP; \ + (opts)->endpoint.tcp.ip = ip_; \ + (opts)->endpoint.tcp.port = port_; \ + } while(0) + +#define REDIS_OPTIONS_SET_UNIX(opts, path) do { \ + (opts)->type = REDIS_CONN_UNIX; \ + (opts)->endpoint.unix_socket = path; \ + } while(0) + +#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) do { \ + (opts)->privdata = data; \ + (opts)->free_privdata = dtor; \ + } while(0) + +typedef struct redisContextFuncs { + void (*close)(struct redisContext *); + void (*free_privctx)(void *); + void (*async_read)(struct redisAsyncContext *); + void (*async_write)(struct redisAsyncContext *); + + /* Read/Write data to the underlying communication stream, returning the + * number of bytes read/written. In the event of an unrecoverable error + * these functions shall return a value < 0. In the event of a + * recoverable error, they should return 0. */ + ssize_t (*read)(struct redisContext *, char *, size_t); + ssize_t (*write)(struct redisContext *); +} redisContextFuncs; + + +/* Context for a connection to Redis */ +typedef struct redisContext { + const redisContextFuncs *funcs; /* Function table */ + + int err; /* Error flags, 0 when there is no error */ + char errstr[128]; /* String representation of error when applicable */ + redisFD fd; + int flags; + char *obuf; /* Write buffer */ + redisReader *reader; /* Protocol reader */ + + enum redisConnectionType connection_type; + struct timeval *connect_timeout; + struct timeval *command_timeout; + + struct { + char *host; + char *source_addr; + int port; + } tcp; + + struct { + char *path; + } unix_sock; + + /* For non-blocking connect */ + struct sockaddr *saddr; + size_t addrlen; + + /* Optional data and corresponding destructor users can use to provide + * context to a given redisContext. Not used by hiredis. */ + void *privdata; + void (*free_privdata)(void *); + + /* Internal context pointer presently used by hiredis to manage + * SSL connections. */ + void *privctx; + + /* An optional RESP3 PUSH handler */ + redisPushFn *push_cb; +} redisContext; + +redisContext *redisConnectWithOptions(const redisOptions *options); +redisContext *redisConnect(const char *ip, int port); +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); +redisContext *redisConnectNonBlock(const char *ip, int port); +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectUnix(const char *path); +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); +redisContext *redisConnectUnixNonBlock(const char *path); +redisContext *redisConnectFd(redisFD fd); + +/** + * Reconnect the given context using the saved information. + * + * This re-uses the exact same connect options as in the initial connection. + * host, ip (or path), timeout and bind address are reused, + * flags are used unmodified from the existing context. + * + * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. + */ +int redisReconnect(redisContext *c); + +redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); +int redisSetTimeout(redisContext *c, const struct timeval tv); +int redisEnableKeepAlive(redisContext *c); +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); +int redisBufferWrite(redisContext *c, int *done); + +/* In a blocking context, this function first checks if there are unconsumed + * replies to return and returns one if so. Otherwise, it flushes the output + * buffer to the socket and reads until it has a reply. In a non-blocking + * context, it will return unconsumed replies until there are no more. */ +int redisGetReply(redisContext *c, void **reply); +int redisGetReplyFromReader(redisContext *c, void **reply); + +/* Write a formatted command to the output buffer. Use these functions in blocking mode + * to get a pipeline of commands. */ +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); + +/* Write a command to the output buffer. Use these functions in blocking mode + * to get a pipeline of commands. */ +int redisvAppendCommand(redisContext *c, const char *format, va_list ap); +int redisAppendCommand(redisContext *c, const char *format, ...); +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + +/* Issue a command to Redis. In a blocking context, it is identical to calling + * redisAppendCommand, followed by redisGetReply. The function will return + * NULL if there was an error in performing the request, otherwise it will + * return the reply. In a non-blocking context, it is identical to calling + * only redisAppendCommand and will always return NULL. */ +void *redisvCommand(redisContext *c, const char *format, va_list ap); +void *redisCommand(redisContext *c, const char *format, ...); +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hiredict.pc.in b/hiredict.pc.in new file mode 100644 index 0000000..c7b8e0e --- /dev/null +++ b/hiredict.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +install_libdir=@CMAKE_INSTALL_LIBDIR@ +exec_prefix=${prefix} +libdir=${exec_prefix}/${install_libdir} +includedir=${prefix}/include +pkgincludedir=${includedir}/hiredis + +Name: hiredis +Description: Minimalistic C client library for Redis. +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -lhiredis +Cflags: -I${pkgincludedir} -I${includedir} -D_FILE_OFFSET_BITS=64 diff --git a/hiredict.targets b/hiredict.targets new file mode 100644 index 0000000..effd8a5 --- /dev/null +++ b/hiredict.targets @@ -0,0 +1,11 @@ + + + + + $(MSBuildThisFileDirectory)\..\..\include;%(AdditionalIncludeDirectories) + + + $(MSBuildThisFileDirectory)\..\..\lib;%(AdditionalLibraryDirectories) + + + \ No newline at end of file diff --git a/hiredict_ssl-config.cmake.in b/hiredict_ssl-config.cmake.in new file mode 100644 index 0000000..eeb19d1 --- /dev/null +++ b/hiredict_ssl-config.cmake.in @@ -0,0 +1,16 @@ +@PACKAGE_INIT@ + +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() + +SET(hiredis_ssl_LIBRARIES hiredis::hiredis_ssl) +SET(hiredis_ssl_INCLUDE_DIRS ${hiredis_ssl_INCLUDEDIR}) + +check_required_components(hiredis_ssl) + diff --git a/hiredict_ssl.h b/hiredict_ssl.h new file mode 100644 index 0000000..43f072a --- /dev/null +++ b/hiredict_ssl.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2019, Redis Labs + * + * SPDX-FileCopyrightText: 2024 Hiredict Contributors + * SPDX-FileCopyrightText: 2024 Redis Labs + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: LGPL-3.0-or-later + * + */ + +#ifndef __HIREDIS_SSL_H +#define __HIREDIS_SSL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the underlying struct for SSL in ssl.h, which is not included to + * keep build dependencies short here. + */ +struct ssl_st; + +/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly + * calling OpenSSL. + */ +typedef struct redisSSLContext redisSSLContext; + +/** + * Initialization errors that redisCreateSSLContext() may return. + */ + +typedef enum { + REDIS_SSL_CTX_NONE = 0, /* No Error */ + REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */ + REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */ + REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */ + REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ + REDIS_SSL_CTX_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 certificate store */ + REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */ +} redisSSLContextError; + +/* Constants that mirror OpenSSL's verify modes. By default, + * REDIS_SSL_VERIFY_PEER is used with redisCreateSSLContext(). + * Some Redis clients disable peer verification if there are no + * certificates specified. + */ +#define REDIS_SSL_VERIFY_NONE 0x00 +#define REDIS_SSL_VERIFY_PEER 0x01 +#define REDIS_SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +#define REDIS_SSL_VERIFY_CLIENT_ONCE 0x04 +#define REDIS_SSL_VERIFY_POST_HANDSHAKE 0x08 + +/* Options to create an OpenSSL context. */ +typedef struct { + const char *cacert_filename; + const char *capath; + const char *cert_filename; + const char *private_key_filename; + const char *server_name; + int verify_mode; +} redisSSLOptions; + +/** + * Return the error message corresponding with the specified error code. + */ + +const char *redisSSLContextGetError(redisSSLContextError error); + +/** + * Helper function to initialize the OpenSSL library. + * + * OpenSSL requires one-time initialization before it can be used. Callers should + * call this function only once, and only if OpenSSL is not directly initialized + * elsewhere. + */ +int redisInitOpenSSL(void); + +/** + * Helper function to initialize an OpenSSL context that can be used + * to initiate SSL connections. + * + * cacert_filename is an optional name of a CA certificate/bundle file to load + * and use for validation. + * + * capath is an optional directory path where trusted CA certificate files are + * stored in an OpenSSL-compatible structure. + * + * cert_filename and private_key_filename are optional names of a client side + * certificate and private key files to use for authentication. They need to + * be both specified or omitted. + * + * server_name is an optional and will be used as a server name indication + * (SNI) TLS extension. + * + * If error is non-null, it will be populated in case the context creation fails + * (returning a NULL). + */ + +redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath, + const char *cert_filename, const char *private_key_filename, + const char *server_name, redisSSLContextError *error); + +/** + * Helper function to initialize an OpenSSL context that can be used + * to initiate SSL connections. This is a more extensible version of redisCreateSSLContext(). + * + * options contains a structure of SSL options to use. + * + * If error is non-null, it will be populated in case the context creation fails + * (returning a NULL). +*/ +redisSSLContext *redisCreateSSLContextWithOptions(redisSSLOptions *options, + redisSSLContextError *error); + +/** + * Free a previously created OpenSSL context. + */ +void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx); + +/** + * Initiate SSL on an existing redisContext. + * + * This is similar to redisInitiateSSL() but does not require the caller + * to directly interact with OpenSSL, and instead uses a redisSSLContext + * previously created using redisCreateSSLContext(). + */ + +int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx); + +/** + * Initiate SSL/TLS negotiation on a provided OpenSSL SSL object. + */ + +int redisInitiateSSL(redisContext *c, struct ssl_st *ssl); + +#ifdef __cplusplus +} +#endif + +#endif /* __HIREDIS_SSL_H */ diff --git a/hiredict_ssl.pc.in b/hiredict_ssl.pc.in new file mode 100644 index 0000000..f7bdd99 --- /dev/null +++ b/hiredict_ssl.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +install_libdir=@CMAKE_INSTALL_LIBDIR@ +exec_prefix=${prefix} +libdir=${exec_prefix}/${install_libdir} +includedir=${prefix}/include +pkgincludedir=${includedir}/hiredis + +Name: hiredis_ssl +Description: SSL Support for hiredis. +Version: @PROJECT_VERSION@ +Requires: hiredis +Libs: -L${libdir} -lhiredis_ssl +Libs.private: -lssl -lcrypto diff --git a/hiredis-config.cmake.in b/hiredis-config.cmake.in deleted file mode 100644 index 0339858..0000000 --- a/hiredis-config.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -@PACKAGE_INIT@ - -set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@") - -IF (NOT TARGET hiredis::@hiredis_export_name@) - INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake) -ENDIF() - -SET(hiredis_LIBRARIES hiredis::@hiredis_export_name@) -SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR}) - -check_required_components(hiredis) - diff --git a/hiredis.c b/hiredis.c deleted file mode 100644 index 9d63d92..0000000 --- a/hiredis.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * SPDX-FileCopyrightText: 2024 Hiredict Contributors - * SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo - * SPDX-FileCopyrightText: 2024 Pieter Noordhuis - * SPDX-FileCopyrightText: 2024 Matt Stancliff - * SPDX-FileCopyrightText: 2024 Jan-Erik Rediger - * - * SPDX-License-Identifier: BSD-3-Clause - * SPDX-License-Identifier: LGPL-3.0-or-later - * - */ - -#include "fmacros.h" -#include -#include -#include -#include -#include - -#include "hiredis.h" -#include "net.h" -#include "sds.h" -#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 = { - .close = redisNetClose, - .free_privctx = NULL, - .async_read = redisAsyncRead, - .async_write = redisAsyncWrite, - .read = redisNetRead, - .write = redisNetWrite -}; - -static redisReply *createReplyObject(int type); -static void *createStringObject(const redisReadTask *task, char *str, size_t len); -static void *createArrayObject(const redisReadTask *task, size_t elements); -static void *createIntegerObject(const redisReadTask *task, long long value); -static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len); -static void *createNilObject(const redisReadTask *task); -static void *createBoolObject(const redisReadTask *task, int bval); - -/* Default set of functions to build the reply. Keep in mind that such a - * function returning NULL is interpreted as OOM. */ -static redisReplyObjectFunctions defaultFunctions = { - createStringObject, - createArrayObject, - createIntegerObject, - createDoubleObject, - createNilObject, - createBoolObject, - freeReplyObject -}; - -/* Create a reply object */ -static redisReply *createReplyObject(int type) { - redisReply *r = hi_calloc(1,sizeof(*r)); - - if (r == NULL) - return NULL; - - r->type = type; - return r; -} - -/* Free a reply object */ -void freeReplyObject(void *reply) { - redisReply *r = reply; - size_t j; - - if (r == NULL) - return; - - switch(r->type) { - case REDIS_REPLY_INTEGER: - case REDIS_REPLY_NIL: - case REDIS_REPLY_BOOL: - break; /* Nothing to free */ - case REDIS_REPLY_ARRAY: - case REDIS_REPLY_MAP: - case REDIS_REPLY_ATTR: - case REDIS_REPLY_SET: - case REDIS_REPLY_PUSH: - if (r->element != NULL) { - for (j = 0; j < r->elements; j++) - freeReplyObject(r->element[j]); - hi_free(r->element); - } - break; - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_STRING: - case REDIS_REPLY_DOUBLE: - case REDIS_REPLY_VERB: - case REDIS_REPLY_BIGNUM: - hi_free(r->str); - break; - } - hi_free(r); -} - -static void *createStringObject(const redisReadTask *task, char *str, size_t len) { - redisReply *r, *parent; - char *buf; - - r = createReplyObject(task->type); - if (r == NULL) - return NULL; - - assert(task->type == REDIS_REPLY_ERROR || - task->type == REDIS_REPLY_STATUS || - task->type == REDIS_REPLY_STRING || - task->type == REDIS_REPLY_VERB || - task->type == REDIS_REPLY_BIGNUM); - - /* Copy string value */ - if (task->type == REDIS_REPLY_VERB) { - buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */ - if (buf == NULL) goto oom; - - memcpy(r->vtype,str,3); - r->vtype[3] = '\0'; - memcpy(buf,str+4,len-4); - buf[len-4] = '\0'; - r->len = len - 4; - } else { - buf = hi_malloc(len+1); - if (buf == NULL) goto oom; - - memcpy(buf,str,len); - buf[len] = '\0'; - r->len = len; - } - r->str = buf; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_ATTR || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; - -oom: - freeReplyObject(r); - return NULL; -} - -static void *createArrayObject(const redisReadTask *task, size_t elements) { - redisReply *r, *parent; - - r = createReplyObject(task->type); - if (r == NULL) - return NULL; - - if (elements > 0) { - r->element = hi_calloc(elements,sizeof(redisReply*)); - if (r->element == NULL) { - freeReplyObject(r); - return NULL; - } - } - - r->elements = elements; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_ATTR || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; -} - -static void *createIntegerObject(const redisReadTask *task, long long value) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_INTEGER); - if (r == NULL) - return NULL; - - r->integer = value; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_ATTR || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; -} - -static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) { - redisReply *r, *parent; - - if (len == SIZE_MAX) // Prevents hi_malloc(0) if len equals to SIZE_MAX - return NULL; - - r = createReplyObject(REDIS_REPLY_DOUBLE); - if (r == NULL) - return NULL; - - r->dval = value; - r->str = hi_malloc(len+1); - if (r->str == NULL) { - freeReplyObject(r); - return NULL; - } - - /* The double reply also has the original protocol string representing a - * double as a null terminated string. This way the caller does not need - * to format back for string conversion, especially since Redis does efforts - * to make the string more human readable avoiding the calssical double - * decimal string conversion artifacts. */ - memcpy(r->str, str, len); - r->str[len] = '\0'; - r->len = len; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_ATTR || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; -} - -static void *createNilObject(const redisReadTask *task) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_NIL); - if (r == NULL) - return NULL; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_ATTR || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; -} - -static void *createBoolObject(const redisReadTask *task, int bval) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_BOOL); - if (r == NULL) - return NULL; - - r->integer = bval != 0; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_ATTR || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; -} - -/* Return the number of digits of 'v' when converted to string in radix 10. - * Implementation borrowed from link in redis/src/util.c:string2ll(). */ -static uint32_t countDigits(uint64_t v) { - uint32_t result = 1; - for (;;) { - if (v < 10) return result; - if (v < 100) return result + 1; - if (v < 1000) return result + 2; - if (v < 10000) return result + 3; - v /= 10000U; - result += 4; - } -} - -/* Helper that calculates the bulk length given a certain string length. */ -static size_t bulklen(size_t len) { - return 1+countDigits(len)+2+len+2; -} - -int redisvFormatCommand(char **target, const char *format, va_list ap) { - const char *c = format; - char *cmd = NULL; /* final command */ - int pos; /* position in final command */ - sds curarg, newarg; /* current argument */ - int touched = 0; /* was the current argument touched? */ - char **curargv = NULL, **newargv = NULL; - int argc = 0; - int totlen = 0; - int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */ - int j; - - /* Abort if there is not target to set */ - if (target == NULL) - return -1; - - /* Build the command string accordingly to protocol */ - curarg = sdsempty(); - if (curarg == NULL) - return -1; - - while(*c != '\0') { - if (*c != '%' || c[1] == '\0') { - if (*c == ' ') { - if (touched) { - newargv = hi_realloc(curargv,sizeof(char*)*(argc+1)); - if (newargv == NULL) goto memory_err; - curargv = newargv; - curargv[argc++] = curarg; - totlen += bulklen(sdslen(curarg)); - - /* curarg is put in argv so it can be overwritten. */ - curarg = sdsempty(); - if (curarg == NULL) goto memory_err; - touched = 0; - } - } else { - newarg = sdscatlen(curarg,c,1); - if (newarg == NULL) goto memory_err; - curarg = newarg; - touched = 1; - } - } else { - char *arg; - size_t size; - - /* Set newarg so it can be checked even if it is not touched. */ - newarg = curarg; - - switch(c[1]) { - case 's': - arg = va_arg(ap,char*); - size = strlen(arg); - if (size > 0) - newarg = sdscatlen(curarg,arg,size); - break; - case 'b': - arg = va_arg(ap,char*); - size = va_arg(ap,size_t); - if (size > 0) - newarg = sdscatlen(curarg,arg,size); - break; - case '%': - newarg = sdscat(curarg,"%"); - break; - default: - /* Try to detect printf format */ - { - static const char intfmts[] = "diouxX"; - static const char flags[] = "#0-+ "; - char _format[16]; - const char *_p = c+1; - size_t _l = 0; - va_list _cpy; - - /* Flags */ - while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; - - /* Field width */ - while (*_p != '\0' && isdigit((int) *_p)) _p++; - - /* Precision */ - if (*_p == '.') { - _p++; - while (*_p != '\0' && isdigit((int) *_p)) _p++; - } - - /* Copy va_list before consuming with va_arg */ - va_copy(_cpy,ap); - - /* Make sure we have more characters otherwise strchr() accepts - * '\0' as an integer specifier. This is checked after above - * va_copy() to avoid UB in fmt_invalid's call to va_end(). */ - if (*_p == '\0') goto fmt_invalid; - - /* Integer conversion (without modifiers) */ - if (strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); - goto fmt_valid; - } - - /* Double conversion (without modifiers) */ - if (strchr("eEfFgGaA",*_p) != NULL) { - va_arg(ap,double); - goto fmt_valid; - } - - /* Size: char */ - if (_p[0] == 'h' && _p[1] == 'h') { - _p += 2; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); /* char gets promoted to int */ - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: short */ - if (_p[0] == 'h') { - _p += 1; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); /* short gets promoted to int */ - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: long long */ - if (_p[0] == 'l' && _p[1] == 'l') { - _p += 2; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,long long); - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: long */ - if (_p[0] == 'l') { - _p += 1; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,long); - goto fmt_valid; - } - goto fmt_invalid; - } - - fmt_invalid: - va_end(_cpy); - goto format_err; - - fmt_valid: - _l = (_p+1)-c; - if (_l < sizeof(_format)-2) { - memcpy(_format,c,_l); - _format[_l] = '\0'; - newarg = sdscatvprintf(curarg,_format,_cpy); - - /* Update current position (note: outer blocks - * increment c twice so compensate here) */ - c = _p-1; - } - - va_end(_cpy); - break; - } - } - - if (newarg == NULL) goto memory_err; - curarg = newarg; - - touched = 1; - c++; - if (*c == '\0') - break; - } - c++; - } - - /* Add the last argument if needed */ - if (touched) { - newargv = hi_realloc(curargv,sizeof(char*)*(argc+1)); - if (newargv == NULL) goto memory_err; - curargv = newargv; - curargv[argc++] = curarg; - totlen += bulklen(sdslen(curarg)); - } else { - sdsfree(curarg); - } - - /* Clear curarg because it was put in curargv or was free'd. */ - curarg = NULL; - - /* Add bytes needed to hold multi bulk count */ - totlen += 1+countDigits(argc)+2; - - /* Build the command at protocol level */ - cmd = hi_malloc(totlen+1); - if (cmd == NULL) goto memory_err; - - pos = sprintf(cmd,"*%d\r\n",argc); - for (j = 0; j < argc; j++) { - pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); - memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); - pos += sdslen(curargv[j]); - sdsfree(curargv[j]); - cmd[pos++] = '\r'; - cmd[pos++] = '\n'; - } - assert(pos == totlen); - cmd[pos] = '\0'; - - hi_free(curargv); - *target = cmd; - return totlen; - -format_err: - error_type = -2; - goto cleanup; - -memory_err: - error_type = -1; - goto cleanup; - -cleanup: - if (curargv) { - while(argc--) - sdsfree(curargv[argc]); - hi_free(curargv); - } - - sdsfree(curarg); - hi_free(cmd); - - return error_type; -} - -/* Format a command according to the Redis protocol. This function - * takes a format similar to printf: - * - * %s represents a C null terminated string you want to interpolate - * %b represents a binary safe string - * - * When using %b you need to provide both the pointer to the string - * and the length in bytes as a size_t. Examples: - * - * len = redisFormatCommand(target, "GET %s", mykey); - * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen); - */ -int redisFormatCommand(char **target, const char *format, ...) { - va_list ap; - int len; - va_start(ap,format); - len = redisvFormatCommand(target,format,ap); - va_end(ap); - - /* The API says "-1" means bad result, but we now also return "-2" in some - * cases. Force the return value to always be -1. */ - if (len < 0) - len = -1; - - return len; -} - -/* Format a command according to the Redis protocol using an sds string and - * sdscatfmt for the processing of arguments. This function takes the - * number of arguments, an array with arguments and an array with their - * lengths. If the latter is set to NULL, strlen will be used to compute the - * argument lengths. - */ -long long redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, - const size_t *argvlen) -{ - sds cmd, aux; - unsigned long long totlen, len; - int j; - - /* Abort on a NULL target */ - if (target == NULL) - return -1; - - /* Calculate our total size */ - totlen = 1+countDigits(argc)+2; - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - totlen += bulklen(len); - } - - /* Use an SDS string for command construction */ - cmd = sdsempty(); - if (cmd == NULL) - return -1; - - /* We already know how much storage we need */ - aux = sdsMakeRoomFor(cmd, totlen); - if (aux == NULL) { - sdsfree(cmd); - return -1; - } - - cmd = aux; - - /* Construct command */ - cmd = sdscatfmt(cmd, "*%i\r\n", argc); - for (j=0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - cmd = sdscatfmt(cmd, "$%U\r\n", len); - cmd = sdscatlen(cmd, argv[j], len); - cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); - } - - assert(sdslen(cmd)==totlen); - - *target = cmd; - return totlen; -} - -void redisFreeSdsCommand(sds cmd) { - sdsfree(cmd); -} - -/* Format a command according to the Redis protocol. This function takes the - * number of arguments, an array with arguments and an array with their - * lengths. If the latter is set to NULL, strlen will be used to compute the - * argument lengths. - */ -long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) { - char *cmd = NULL; /* final command */ - size_t pos; /* position in final command */ - size_t len, totlen; - int j; - - /* Abort on a NULL target */ - if (target == NULL) - return -1; - - /* Calculate number of bytes needed for the command */ - totlen = 1+countDigits(argc)+2; - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - totlen += bulklen(len); - } - - /* Build the command at protocol level */ - cmd = hi_malloc(totlen+1); - if (cmd == NULL) - return -1; - - pos = sprintf(cmd,"*%d\r\n",argc); - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - pos += sprintf(cmd+pos,"$%zu\r\n",len); - memcpy(cmd+pos,argv[j],len); - pos += len; - cmd[pos++] = '\r'; - cmd[pos++] = '\n'; - } - assert(pos == totlen); - cmd[pos] = '\0'; - - *target = cmd; - return totlen; -} - -void redisFreeCommand(char *cmd) { - hi_free(cmd); -} - -void __redisSetError(redisContext *c, int type, const char *str) { - size_t len; - - c->err = type; - if (str != NULL) { - len = strlen(str); - len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1); - memcpy(c->errstr,str,len); - c->errstr[len] = '\0'; - } else { - /* Only REDIS_ERR_IO may lack a description! */ - assert(type == REDIS_ERR_IO); - strerror_r(errno, c->errstr, sizeof(c->errstr)); - } -} - -redisReader *redisReaderCreate(void) { - return redisReaderCreateWithFunctions(&defaultFunctions); -} - -static void redisPushAutoFree(void *privdata, void *reply) { - (void)privdata; - freeReplyObject(reply); -} - -static redisContext *redisContextInit(void) { - redisContext *c; - - c = hi_calloc(1, sizeof(*c)); - if (c == NULL) - return NULL; - - c->funcs = &redisContextDefaultFuncs; - - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - c->fd = REDIS_INVALID_FD; - - if (c->obuf == NULL || c->reader == NULL) { - redisFree(c); - return NULL; - } - - return c; -} - -void redisFree(redisContext *c) { - if (c == NULL) - return; - - if (c->funcs && c->funcs->close) { - c->funcs->close(c); - } - - sdsfree(c->obuf); - redisReaderFree(c->reader); - hi_free(c->tcp.host); - hi_free(c->tcp.source_addr); - hi_free(c->unix_sock.path); - hi_free(c->connect_timeout); - hi_free(c->command_timeout); - hi_free(c->saddr); - - if (c->privdata && c->free_privdata) - c->free_privdata(c->privdata); - - if (c->funcs && c->funcs->free_privctx) - c->funcs->free_privctx(c->privctx); - - memset(c, 0xff, sizeof(*c)); - hi_free(c); -} - -redisFD redisFreeKeepFd(redisContext *c) { - redisFD fd = c->fd; - c->fd = REDIS_INVALID_FD; - redisFree(c); - return fd; -} - -int redisReconnect(redisContext *c) { - c->err = 0; - memset(c->errstr, '\0', strlen(c->errstr)); - - if (c->privctx && c->funcs->free_privctx) { - c->funcs->free_privctx(c->privctx); - c->privctx = NULL; - } - - if (c->funcs && c->funcs->close) { - c->funcs->close(c); - } - - sdsfree(c->obuf); - redisReaderFree(c->reader); - - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - - if (c->obuf == NULL || c->reader == NULL) { - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; - } - - int ret = REDIS_ERR; - if (c->connection_type == REDIS_CONN_TCP) { - ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, - c->connect_timeout, c->tcp.source_addr); - } else if (c->connection_type == REDIS_CONN_UNIX) { - 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; - } - - 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(); - if (c == NULL) { - return NULL; - } - if (!(options->options & REDIS_OPT_NONBLOCK)) { - c->flags |= REDIS_BLOCK; - } - if (options->options & REDIS_OPT_REUSEADDR) { - c->flags |= REDIS_REUSEADDR; - } - if (options->options & REDIS_OPT_NOAUTOFREE) { - c->flags |= REDIS_NO_AUTO_FREE; - } - if (options->options & REDIS_OPT_NOAUTOFREEREPLIES) { - c->flags |= REDIS_NO_AUTO_FREE_REPLIES; - } - if (options->options & REDIS_OPT_PREFER_IPV4) { - c->flags |= REDIS_PREFER_IPV4; - } - if (options->options & REDIS_OPT_PREFER_IPV6) { - c->flags |= REDIS_PREFER_IPV6; - } - - /* 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->connect_timeout, - options->endpoint.tcp.source_addr); - } else if (options->type == REDIS_CONN_UNIX) { - redisContextConnectUnix(c, options->endpoint.unix_socket, - options->connect_timeout); - } else if (options->type == REDIS_CONN_USERFD) { - c->fd = options->endpoint.fd; - c->flags |= REDIS_CONNECTED; - } else { - redisFree(c); - return NULL; - } - - if (c->err == 0 && c->fd != REDIS_INVALID_FD && - options->command_timeout != NULL && (c->flags & REDIS_BLOCK)) - { - redisContextSetTimeout(c, *options->command_timeout); - } - - return c; -} - -/* Connect to a Redis instance. On error the field error in the returned - * context will be set to the return value of the error function. - * When no set of reply functions is given, the default set will be used. */ -redisContext *redisConnect(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.connect_timeout = &tv; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectNonBlock(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectBindNonBlock(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnix(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - options.connect_timeout = &tv; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnixNonBlock(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectFd(redisFD fd) { - redisOptions options = {0}; - options.type = REDIS_CONN_USERFD; - options.endpoint.fd = fd; - return redisConnectWithOptions(&options); -} - -/* Set read/write timeout on a blocking socket. */ -int redisSetTimeout(redisContext *c, const struct timeval tv) { - if (c->flags & REDIS_BLOCK) - return redisContextSetTimeout(c,tv); - return REDIS_ERR; -} - -int redisEnableKeepAliveWithInterval(redisContext *c, int interval) { - return redisKeepAlive(c, interval); -} - -/* Enable connection KeepAlive. */ -int redisEnableKeepAlive(redisContext *c) { - 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. */ -redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) { - redisPushFn *old = c->push_cb; - c->push_cb = fn; - return old; -} - -/* Use this function to handle a read event on the descriptor. It will try - * and read some bytes from the socket and feed them to the reply parser. - * - * After this function is called, you may use redisGetReplyFromReader to - * see if there is a reply available. */ -int redisBufferRead(redisContext *c) { - char buf[1024*16]; - int nread; - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - nread = c->funcs->read(c, buf, sizeof(buf)); - if (nread < 0) { - return REDIS_ERR; - } - if (nread > 0 && redisReaderFeed(c->reader, buf, nread) != REDIS_OK) { - __redisSetError(c, c->reader->err, c->reader->errstr); - return REDIS_ERR; - } - return REDIS_OK; -} - -/* Write the output buffer to the socket. - * - * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was - * successfully written to the socket. When the buffer is empty after the - * write operation, "done" is set to 1 (if given). - * - * Returns REDIS_ERR if an unrecoverable error occurred in the underlying - * c->funcs->write function. - */ -int redisBufferWrite(redisContext *c, int *done) { - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - if (sdslen(c->obuf) > 0) { - ssize_t nwritten = c->funcs->write(c); - if (nwritten < 0) { - return REDIS_ERR; - } else if (nwritten > 0) { - if (nwritten == (ssize_t)sdslen(c->obuf)) { - sdsfree(c->obuf); - c->obuf = sdsempty(); - if (c->obuf == NULL) - goto oom; - } else { - if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom; - } - } - } - if (done != NULL) *done = (sdslen(c->obuf) == 0); - return REDIS_OK; - -oom: - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; -} - -/* Internal helper that returns 1 if the reply was a RESP3 PUSH - * message and we handled it with a user-provided callback. */ -static int redisHandledPushReply(redisContext *c, void *reply) { - if (reply && c->push_cb && redisIsPushReply(reply)) { - c->push_cb(c->privdata, reply); - return 1; - } - - return 0; -} - -/* Get a reply from our reader or set an error in the context. */ -int redisGetReplyFromReader(redisContext *c, void **reply) { - if (redisReaderGetReply(c->reader, reply) == REDIS_ERR) { - __redisSetError(c,c->reader->err,c->reader->errstr); - return REDIS_ERR; - } - - return REDIS_OK; -} - -/* Internal helper to get the next reply from our reader while handling - * any PUSH messages we encounter along the way. This is separate from - * redisGetReplyFromReader so as to not change its behavior. */ -static int redisNextInBandReplyFromReader(redisContext *c, void **reply) { - do { - if (redisGetReplyFromReader(c, reply) == REDIS_ERR) - return REDIS_ERR; - } while (redisHandledPushReply(c, *reply)); - - return REDIS_OK; -} - -int redisGetReply(redisContext *c, void **reply) { - int wdone = 0; - void *aux = NULL; - - /* Try to read pending replies */ - if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - - /* For the blocking context, flush output buffer and read reply */ - if (aux == NULL && c->flags & REDIS_BLOCK) { - /* Write until done */ - do { - if (redisBufferWrite(c,&wdone) == REDIS_ERR) - return REDIS_ERR; - } while (!wdone); - - /* Read until there is a reply */ - do { - if (redisBufferRead(c) == REDIS_ERR) - return REDIS_ERR; - - if (redisNextInBandReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - } while (aux == NULL); - } - - /* Set reply or free it if we were passed NULL */ - if (reply != NULL) { - *reply = aux; - } else { - freeReplyObject(aux); - } - - return REDIS_OK; -} - - -/* Helper function for the redisAppendCommand* family of functions. - * - * Write a formatted command to the output buffer. When this family - * is used, you need to call redisGetReply yourself to retrieve - * the reply (or replies in pub/sub). - */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) { - sds newbuf; - - newbuf = sdscatlen(c->obuf,cmd,len); - if (newbuf == NULL) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - c->obuf = newbuf; - return REDIS_OK; -} - -int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) { - - if (__redisAppendCommand(c, cmd, len) != REDIS_OK) { - return REDIS_ERR; - } - - return REDIS_OK; -} - -int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { - char *cmd; - int len; - - len = redisvFormatCommand(&cmd,format,ap); - if (len == -1) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } else if (len == -2) { - __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string"); - return REDIS_ERR; - } - - if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - hi_free(cmd); - return REDIS_ERR; - } - - hi_free(cmd); - return REDIS_OK; -} - -int redisAppendCommand(redisContext *c, const char *format, ...) { - va_list ap; - int ret; - - va_start(ap,format); - ret = redisvAppendCommand(c,format,ap); - va_end(ap); - return ret; -} - -int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { - sds cmd; - long long len; - - len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); - if (len == -1) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - sdsfree(cmd); - return REDIS_ERR; - } - - sdsfree(cmd); - return REDIS_OK; -} - -/* Helper function for the redisCommand* family of functions. - * - * Write a formatted command to the output buffer. If the given context is - * blocking, immediately read the reply into the "reply" pointer. When the - * context is non-blocking, the "reply" pointer will not be used and the - * command is simply appended to the write buffer. - * - * Returns the reply when a reply was successfully retrieved. Returns NULL - * otherwise. When NULL is returned in a blocking context, the error field - * in the context will be set. - */ -static void *__redisBlockForReply(redisContext *c) { - void *reply; - - if (c->flags & REDIS_BLOCK) { - if (redisGetReply(c,&reply) != REDIS_OK) - return NULL; - return reply; - } - return NULL; -} - -void *redisvCommand(redisContext *c, const char *format, va_list ap) { - if (redisvAppendCommand(c,format,ap) != REDIS_OK) - return NULL; - return __redisBlockForReply(c); -} - -void *redisCommand(redisContext *c, const char *format, ...) { - va_list ap; - va_start(ap,format); - void *reply = redisvCommand(c,format,ap); - va_end(ap); - return reply; -} - -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { - if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK) - return NULL; - return __redisBlockForReply(c); -} diff --git a/hiredis.h b/hiredis.h deleted file mode 100644 index 1936b4d..0000000 --- a/hiredis.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * SPDX-FileCopyrightText: 2024 Hiredict Contributors - * SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo - * SPDX-FileCopyrightText: 2024 Pieter Noordhuis - * SPDX-FileCopyrightText: 2024 Matt Stancliff - * SPDX-FileCopyrightText: 2024 Jan-Erik Rediger - * - * SPDX-License-Identifier: BSD-3-Clause - * SPDX-License-Identifier: LGPL-3.0-or-later - * - */ - -#ifndef __HIREDIS_H -#define __HIREDIS_H -#include "read.h" -#include /* for va_list */ -#ifndef _MSC_VER -#include /* for struct timeval */ -#else -struct timeval; /* forward declaration */ -typedef long long ssize_t; -#endif -#include /* uintXX_t, etc */ -#include "sds.h" /* for sds */ -#include "alloc.h" /* for allocation wrappers */ - -#define HIREDIS_MAJOR 1 -#define HIREDIS_MINOR 2 -#define HIREDIS_PATCH 0 -#define HIREDIS_SONAME 1.2.1-dev - -/* Connection type can be blocking or non-blocking and is set in the - * least significant bit of the flags field in redisContext. */ -#define REDIS_BLOCK 0x1 - -/* Connection may be disconnected before being free'd. The second bit - * in the flags field is set when the context is connected. */ -#define REDIS_CONNECTED 0x2 - -/* The async API might try to disconnect cleanly and flush the output - * buffer and read all subsequent replies before disconnecting. - * This flag means no new commands can come in and the connection - * should be terminated once all replies have been read. */ -#define REDIS_DISCONNECTING 0x4 - -/* Flag specific to the async API which means that the context should be clean - * up as soon as possible. */ -#define REDIS_FREEING 0x8 - -/* Flag that is set when an async callback is executed. */ -#define REDIS_IN_CALLBACK 0x10 - -/* Flag that is set when the async context has one or more subscriptions. */ -#define REDIS_SUBSCRIBED 0x20 - -/* Flag that is set when monitor mode is active */ -#define REDIS_MONITORING 0x40 - -/* Flag that is set when we should set SO_REUSEADDR before calling bind() */ -#define REDIS_REUSEADDR 0x80 - -/* Flag that is set when the async connection supports push replies. */ -#define REDIS_SUPPORTS_PUSH 0x100 - -/** - * Flag that indicates the user does not want the context to - * be automatically freed upon error - */ -#define REDIS_NO_AUTO_FREE 0x200 - -/* Flag that indicates the user does not want replies to be automatically freed */ -#define REDIS_NO_AUTO_FREE_REPLIES 0x400 - -/* Flags to prefer IPv6 or IPv4 when doing DNS lookup. (If both are set, - * AF_UNSPEC is used.) */ -#define REDIS_PREFER_IPV4 0x800 -#define REDIS_PREFER_IPV6 0x1000 - -#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ - -/* number of times we retry to connect in the case of EADDRNOTAVAIL and - * SO_REUSEADDR is being used. */ -#define REDIS_CONNECT_RETRIES 10 - -/* Forward declarations for structs defined elsewhere */ -struct redisAsyncContext; -struct redisContext; - -/* RESP3 push helpers and callback prototypes */ -#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH) -typedef void (redisPushFn)(void *, void *); -typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *); - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the reply object returned by redisCommand() */ -typedef struct redisReply { - int type; /* REDIS_REPLY_* */ - long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ - double dval; /* The double when type is REDIS_REPLY_DOUBLE */ - size_t len; /* Length of string */ - char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING - REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval), - and REDIS_REPLY_BIGNUM. */ - char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null - terminated 3 character content type, such as "txt". */ - size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ - struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ -} redisReply; - -redisReader *redisReaderCreate(void); - -/* Function to free the reply objects hiredis returns by default. */ -void freeReplyObject(void *reply); - -/* Functions to format a command according to the protocol. */ -int redisvFormatCommand(char **target, const char *format, va_list ap); -int redisFormatCommand(char **target, const char *format, ...); -long long redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); -long long redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); -void redisFreeCommand(char *cmd); -void redisFreeSdsCommand(sds cmd); - -enum redisConnectionType { - REDIS_CONN_TCP, - REDIS_CONN_UNIX, - REDIS_CONN_USERFD -}; - -struct redisSsl; - -#define REDIS_OPT_NONBLOCK 0x01 -#define REDIS_OPT_REUSEADDR 0x02 -#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) - -/* In Unix systems a file descriptor is a regular signed int, with -1 - * representing an invalid descriptor. In Windows it is a SOCKET - * (32- or 64-bit unsigned integer depending on the architecture), where - * all bits set (~0) is INVALID_SOCKET. */ -#ifndef _WIN32 -typedef int redisFD; -#define REDIS_INVALID_FD -1 -#else -#ifdef _WIN64 -typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */ -#else -typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */ -#endif -#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */ -#endif - -typedef struct { - /* - * the type of connection to use. This also indicates which - * `endpoint` member field to use - */ - int type; - /* bit field of REDIS_OPT_xxx */ - int options; - /* timeout value for connect operation. If NULL, no timeout is used */ - const struct timeval *connect_timeout; - /* timeout value for commands. If NULL, no timeout is used. This can be - * updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */ - const struct timeval *command_timeout; - union { - /** use this field for tcp/ip connections */ - struct { - const char *source_addr; - const char *ip; - int port; - } tcp; - /** use this field for unix domain sockets */ - const char *unix_socket; - /** - * use this field to have hiredis operate an already-open - * file descriptor */ - redisFD fd; - } endpoint; - - /* Optional user defined data/destructor */ - void *privdata; - void (*free_privdata)(void *); - - /* A user defined PUSH message callback */ - redisPushFn *push_cb; - redisAsyncPushFn *async_push_cb; -} redisOptions; - -/** - * Helper macros to initialize options to their specified fields. - */ -#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) do { \ - (opts)->type = REDIS_CONN_TCP; \ - (opts)->endpoint.tcp.ip = ip_; \ - (opts)->endpoint.tcp.port = port_; \ - } while(0) - -#define REDIS_OPTIONS_SET_UNIX(opts, path) do { \ - (opts)->type = REDIS_CONN_UNIX; \ - (opts)->endpoint.unix_socket = path; \ - } while(0) - -#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) do { \ - (opts)->privdata = data; \ - (opts)->free_privdata = dtor; \ - } while(0) - -typedef struct redisContextFuncs { - void (*close)(struct redisContext *); - void (*free_privctx)(void *); - void (*async_read)(struct redisAsyncContext *); - void (*async_write)(struct redisAsyncContext *); - - /* Read/Write data to the underlying communication stream, returning the - * number of bytes read/written. In the event of an unrecoverable error - * these functions shall return a value < 0. In the event of a - * recoverable error, they should return 0. */ - ssize_t (*read)(struct redisContext *, char *, size_t); - ssize_t (*write)(struct redisContext *); -} redisContextFuncs; - - -/* Context for a connection to Redis */ -typedef struct redisContext { - const redisContextFuncs *funcs; /* Function table */ - - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - redisFD fd; - int flags; - char *obuf; /* Write buffer */ - redisReader *reader; /* Protocol reader */ - - enum redisConnectionType connection_type; - struct timeval *connect_timeout; - struct timeval *command_timeout; - - struct { - char *host; - char *source_addr; - int port; - } tcp; - - struct { - char *path; - } unix_sock; - - /* For non-blocking connect */ - struct sockaddr *saddr; - size_t addrlen; - - /* Optional data and corresponding destructor users can use to provide - * context to a given redisContext. Not used by hiredis. */ - void *privdata; - void (*free_privdata)(void *); - - /* Internal context pointer presently used by hiredis to manage - * SSL connections. */ - void *privctx; - - /* An optional RESP3 PUSH handler */ - redisPushFn *push_cb; -} redisContext; - -redisContext *redisConnectWithOptions(const redisOptions *options); -redisContext *redisConnect(const char *ip, int port); -redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); -redisContext *redisConnectNonBlock(const char *ip, int port); -redisContext *redisConnectBindNonBlock(const char *ip, int port, - const char *source_addr); -redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, - const char *source_addr); -redisContext *redisConnectUnix(const char *path); -redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); -redisContext *redisConnectUnixNonBlock(const char *path); -redisContext *redisConnectFd(redisFD fd); - -/** - * Reconnect the given context using the saved information. - * - * This re-uses the exact same connect options as in the initial connection. - * host, ip (or path), timeout and bind address are reused, - * flags are used unmodified from the existing context. - * - * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. - */ -int redisReconnect(redisContext *c); - -redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); -int redisSetTimeout(redisContext *c, const struct timeval tv); -int redisEnableKeepAlive(redisContext *c); -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); -int redisBufferWrite(redisContext *c, int *done); - -/* In a blocking context, this function first checks if there are unconsumed - * replies to return and returns one if so. Otherwise, it flushes the output - * buffer to the socket and reads until it has a reply. In a non-blocking - * context, it will return unconsumed replies until there are no more. */ -int redisGetReply(redisContext *c, void **reply); -int redisGetReplyFromReader(redisContext *c, void **reply); - -/* Write a formatted command to the output buffer. Use these functions in blocking mode - * to get a pipeline of commands. */ -int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); - -/* Write a command to the output buffer. Use these functions in blocking mode - * to get a pipeline of commands. */ -int redisvAppendCommand(redisContext *c, const char *format, va_list ap); -int redisAppendCommand(redisContext *c, const char *format, ...); -int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); - -/* Issue a command to Redis. In a blocking context, it is identical to calling - * redisAppendCommand, followed by redisGetReply. The function will return - * NULL if there was an error in performing the request, otherwise it will - * return the reply. In a non-blocking context, it is identical to calling - * only redisAppendCommand and will always return NULL. */ -void *redisvCommand(redisContext *c, const char *format, va_list ap); -void *redisCommand(redisContext *c, const char *format, ...); -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/hiredis.pc.in b/hiredis.pc.in deleted file mode 100644 index c7b8e0e..0000000 --- a/hiredis.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -install_libdir=@CMAKE_INSTALL_LIBDIR@ -exec_prefix=${prefix} -libdir=${exec_prefix}/${install_libdir} -includedir=${prefix}/include -pkgincludedir=${includedir}/hiredis - -Name: hiredis -Description: Minimalistic C client library for Redis. -Version: @PROJECT_VERSION@ -Libs: -L${libdir} -lhiredis -Cflags: -I${pkgincludedir} -I${includedir} -D_FILE_OFFSET_BITS=64 diff --git a/hiredis.targets b/hiredis.targets deleted file mode 100644 index effd8a5..0000000 --- a/hiredis.targets +++ /dev/null @@ -1,11 +0,0 @@ - - - - - $(MSBuildThisFileDirectory)\..\..\include;%(AdditionalIncludeDirectories) - - - $(MSBuildThisFileDirectory)\..\..\lib;%(AdditionalLibraryDirectories) - - - \ No newline at end of file diff --git a/hiredis_ssl-config.cmake.in b/hiredis_ssl-config.cmake.in deleted file mode 100644 index eeb19d1..0000000 --- a/hiredis_ssl-config.cmake.in +++ /dev/null @@ -1,16 +0,0 @@ -@PACKAGE_INIT@ - -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() - -SET(hiredis_ssl_LIBRARIES hiredis::hiredis_ssl) -SET(hiredis_ssl_INCLUDE_DIRS ${hiredis_ssl_INCLUDEDIR}) - -check_required_components(hiredis_ssl) - diff --git a/hiredis_ssl.h b/hiredis_ssl.h deleted file mode 100644 index 43f072a..0000000 --- a/hiredis_ssl.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2019, Redis Labs - * - * SPDX-FileCopyrightText: 2024 Hiredict Contributors - * SPDX-FileCopyrightText: 2024 Redis Labs - * - * SPDX-License-Identifier: BSD-3-Clause - * SPDX-License-Identifier: LGPL-3.0-or-later - * - */ - -#ifndef __HIREDIS_SSL_H -#define __HIREDIS_SSL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the underlying struct for SSL in ssl.h, which is not included to - * keep build dependencies short here. - */ -struct ssl_st; - -/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly - * calling OpenSSL. - */ -typedef struct redisSSLContext redisSSLContext; - -/** - * Initialization errors that redisCreateSSLContext() may return. - */ - -typedef enum { - REDIS_SSL_CTX_NONE = 0, /* No Error */ - REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */ - REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */ - REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */ - REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ - REDIS_SSL_CTX_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 certificate store */ - REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */ -} redisSSLContextError; - -/* Constants that mirror OpenSSL's verify modes. By default, - * REDIS_SSL_VERIFY_PEER is used with redisCreateSSLContext(). - * Some Redis clients disable peer verification if there are no - * certificates specified. - */ -#define REDIS_SSL_VERIFY_NONE 0x00 -#define REDIS_SSL_VERIFY_PEER 0x01 -#define REDIS_SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 -#define REDIS_SSL_VERIFY_CLIENT_ONCE 0x04 -#define REDIS_SSL_VERIFY_POST_HANDSHAKE 0x08 - -/* Options to create an OpenSSL context. */ -typedef struct { - const char *cacert_filename; - const char *capath; - const char *cert_filename; - const char *private_key_filename; - const char *server_name; - int verify_mode; -} redisSSLOptions; - -/** - * Return the error message corresponding with the specified error code. - */ - -const char *redisSSLContextGetError(redisSSLContextError error); - -/** - * Helper function to initialize the OpenSSL library. - * - * OpenSSL requires one-time initialization before it can be used. Callers should - * call this function only once, and only if OpenSSL is not directly initialized - * elsewhere. - */ -int redisInitOpenSSL(void); - -/** - * Helper function to initialize an OpenSSL context that can be used - * to initiate SSL connections. - * - * cacert_filename is an optional name of a CA certificate/bundle file to load - * and use for validation. - * - * capath is an optional directory path where trusted CA certificate files are - * stored in an OpenSSL-compatible structure. - * - * cert_filename and private_key_filename are optional names of a client side - * certificate and private key files to use for authentication. They need to - * be both specified or omitted. - * - * server_name is an optional and will be used as a server name indication - * (SNI) TLS extension. - * - * If error is non-null, it will be populated in case the context creation fails - * (returning a NULL). - */ - -redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath, - const char *cert_filename, const char *private_key_filename, - const char *server_name, redisSSLContextError *error); - -/** - * Helper function to initialize an OpenSSL context that can be used - * to initiate SSL connections. This is a more extensible version of redisCreateSSLContext(). - * - * options contains a structure of SSL options to use. - * - * If error is non-null, it will be populated in case the context creation fails - * (returning a NULL). -*/ -redisSSLContext *redisCreateSSLContextWithOptions(redisSSLOptions *options, - redisSSLContextError *error); - -/** - * Free a previously created OpenSSL context. - */ -void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx); - -/** - * Initiate SSL on an existing redisContext. - * - * This is similar to redisInitiateSSL() but does not require the caller - * to directly interact with OpenSSL, and instead uses a redisSSLContext - * previously created using redisCreateSSLContext(). - */ - -int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx); - -/** - * Initiate SSL/TLS negotiation on a provided OpenSSL SSL object. - */ - -int redisInitiateSSL(redisContext *c, struct ssl_st *ssl); - -#ifdef __cplusplus -} -#endif - -#endif /* __HIREDIS_SSL_H */ diff --git a/hiredis_ssl.pc.in b/hiredis_ssl.pc.in deleted file mode 100644 index f7bdd99..0000000 --- a/hiredis_ssl.pc.in +++ /dev/null @@ -1,13 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -install_libdir=@CMAKE_INSTALL_LIBDIR@ -exec_prefix=${prefix} -libdir=${exec_prefix}/${install_libdir} -includedir=${prefix}/include -pkgincludedir=${includedir}/hiredis - -Name: hiredis_ssl -Description: SSL Support for hiredis. -Version: @PROJECT_VERSION@ -Requires: hiredis -Libs: -L${libdir} -lhiredis_ssl -Libs.private: -lssl -lcrypto diff --git a/net.h b/net.h index bebaab8..d9bc357 100644 --- a/net.h +++ b/net.h @@ -19,7 +19,7 @@ #ifndef __NET_H #define __NET_H -#include "hiredis.h" +#include "hiredict.h" void redisNetClose(redisContext *c); ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap); diff --git a/ssl.c b/ssl.c index 0f0b331..60a9695 100644 --- a/ssl.c +++ b/ssl.c @@ -13,7 +13,7 @@ * */ -#include "hiredis.h" +#include "hiredict.h" #include "async.h" #include "net.h" diff --git a/test.c b/test.c index f769b85..72f94ef 100644 --- a/test.c +++ b/test.c @@ -24,7 +24,7 @@ #include #include -#include "hiredis.h" +#include "hiredict.h" #include "async.h" #include "adapters/poll.h" #ifdef HIREDIS_TEST_SSL -- cgit v1.2.3