Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,6 @@ valkey
Valkey
VALKEY
variadic
DNS
FreeBSD
macOS
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,46 @@ jobs:
run: |
sudo USE_RDMA=1 make install

cares:
name: Build with c-ares ${{ matrix.sanitizer && format('({0})', matrix.sanitizer) || '' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer: ['', 'thread', 'undefined', 'leak', 'address']
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Prepare
uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0
with:
packages: libc-ares-dev libevent-dev valkey-server
version: 1.0
- name: Build with make
run: USE_CARES=1 make
- name: Build with CMake
run: |
CFLAGS=""
if [ -n "${{ matrix.sanitizer }}" ]; then
CFLAGS="-fno-omit-frame-pointer -fsanitize=${{ matrix.sanitizer }}"
fi
cmake -B build -S . -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_CARES=ON -DENABLE_IPV6_TESTS=ON -DCMAKE_C_FLAGS="$CFLAGS"
- name: Build
working-directory: build
run: make
- name: Setup clusters
working-directory: build
run: make start
- name: Wait for clusters to start..
uses: kibertoad/wait-action@99f6f101c5be7b88bb9b41c0d3b810722491b8e5 # 1.0.1
with:
time: '20s'
- name: Run tests
working-directory: build
run: make test
- name: Teardown clusters
working-directory: build
run: make stop

cmake-minimum-required:
name: CMake 3.7.0 (min. required)
runs-on: ubuntu-latest
Expand Down
28 changes: 28 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ OPTION(ENABLE_EXAMPLES "Enable building valkey examples" OFF)
option(ENABLE_IPV6_TESTS "Enable IPv6 tests requiring special prerequisites" OFF)
OPTION(ENABLE_RDMA "Build valkey_rdma for RDMA support" OFF)
OPTION(ENABLE_DLOPEN_RDMA "Build valkey_rdma with dynamic loading" OFF)
OPTION(ENABLE_CARES "Build with c-ares for non-blocking DNS" OFF)
OPTION(DISABLE_FFC_IMPL "Disable bundled ffc implementation (use external)" OFF)

# Libvalkey requires C99 (-std=c99)
Expand All @@ -48,6 +49,7 @@ set(valkey_sources
src/conn.c
src/crc16.c
src/dict.c
src/dns.c
src/net.c
src/read.c
src/sockcompat.c
Expand Down Expand Up @@ -96,6 +98,25 @@ if(DISABLE_FFC_IMPL)
list(APPEND valkey_compile_definitions DISABLE_FFC_IMPL)
endif()

if(ENABLE_CARES AND NOT WIN32)
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(CARES IMPORTED_TARGET libcares)
endif()
if(CARES_FOUND)
list(APPEND valkey_link_libraries PkgConfig::CARES)
else()
find_library(CARES_LIBRARY NAMES cares)
find_path(CARES_INCLUDE_DIR ares.h)
if(CARES_LIBRARY AND CARES_INCLUDE_DIR)
list(APPEND valkey_link_libraries ${CARES_LIBRARY})
include_directories(${CARES_INCLUDE_DIR})
else()
message(FATAL_ERROR "c-ares not found. Install libcares or disable ENABLE_CARES.")
endif()
endif()
endif()

if(valkey_link_libraries)
target_link_libraries(valkey PUBLIC ${valkey_link_libraries})
endif()
Expand All @@ -104,6 +125,10 @@ if(valkey_compile_definitions)
target_compile_definitions(valkey PRIVATE ${valkey_compile_definitions})
endif()

if(ENABLE_CARES AND NOT WIN32)
target_compile_definitions(valkey PUBLIC VALKEY_USE_CARES)
endif()

TARGET_INCLUDE_DIRECTORIES(valkey
PUBLIC
$<INSTALL_INTERFACE:include>
Expand Down Expand Up @@ -343,6 +368,9 @@ if(NOT DISABLE_TESTS)
if(valkey_compile_definitions)
target_compile_definitions(valkey_unittest PRIVATE ${valkey_compile_definitions})
endif()
if(ENABLE_CARES AND NOT WIN32)
target_compile_definitions(valkey_unittest PRIVATE VALKEY_USE_CARES)
endif()
if(valkey_link_libraries)
target_link_libraries(valkey_unittest PUBLIC ${valkey_link_libraries})
endif()
Expand Down
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ else
endif
##################### RDMA variables end #####################

#################### c-ares variables start ####################
USE_CARES?=0

ifeq ($(USE_CARES),1)
CFLAGS+=-DVALKEY_USE_CARES
CARES_LDFLAGS=-lcares
else
CARES_LDFLAGS=
endif
##################### c-ares variables end #####################

# Platform-specific overrides
uname_S := $(shell uname -s 2>/dev/null || echo not)

Expand Down Expand Up @@ -244,7 +255,7 @@ else ifeq ($(uname_S),Darwin)
-Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(TLS_DYLIB_PATCH_NAME)
endif

REAL_LDFLAGS += $(PTHREAD_FLAGS)
REAL_LDFLAGS += $(PTHREAD_FLAGS) $(CARES_LDFLAGS)

all: dynamic static pkgconfig tests

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Libvalkey is the official C client for the [Valkey](https://valkey.io) database.
- Supports both `RESP2` and `RESP3` protocol versions.
- Supports both synchronous and asynchronous operation.
- Optional support for `MPTCP`, `TLS` and `RDMA` connections.
- Optional timeout-bounded DNS resolution via [c-ares](https://github.com/c-ares/c-ares).
- Asynchronous API with several event libraries to choose from.
- Supports both standalone and cluster mode operation.
- Can be compiled with either `make` or `CMake`.
Expand All @@ -42,7 +43,7 @@ We support plain GNU make and CMake. Following is information on how to build th
sudo make install

# With all options
sudo USE_TLS=1 USE_RDMA=1 make install
sudo USE_TLS=1 USE_RDMA=1 USE_CARES=1 make install

# If your openssl is in a non-default location
sudo USE_TLS=1 OPENSSL_PREFIX=/path/to/openssl make install
Expand All @@ -58,9 +59,9 @@ mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
sudo make install

# Build with TLS and RDMA support
# Build with TLS, RDMA, and c-ares support
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TLS=1 -DENABLE_RDMA=1 ..
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TLS=1 -DENABLE_RDMA=1 -DENABLE_CARES=1 ..
sudo make install
```

Expand Down
2 changes: 1 addition & 1 deletion docs/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ There are also several flags you can specify in `valkeyClusterOptions.options`.
| `VALKEY_OPT_USE_REPLICAS` | Tells libvalkey to keep parsed information of replica nodes. |
| `VALKEY_OPT_BLOCKING_INITIAL_UPDATE` | **ASYNC**: Tells libvalkey to perform the initial slot map update in a blocking fashion. The function call will wait for a slot map update before returning so that the returned context is immediately ready to accept commands. |
| `VALKEY_OPT_REUSEADDR` | Tells libvalkey to set the [SO_REUSEADDR](https://man7.org/linux/man-pages/man7/socket.7.html) socket option |
| `VALKEY_OPT_PREFER_IPV4`<br>`VALKEY_OPT_PREFER_IPV6`<br>`VALKEY_OPT_PREFER_IP_UNSPEC` | Informs libvalkey to either prefer IPv4 or IPv6 when invoking [getaddrinfo](https://man7.org/linux/man-pages/man3/gai_strerror.3.html). `VALKEY_OPT_PREFER_IP_UNSPEC` will cause libvalkey to specify `AF_UNSPEC` in the getaddrinfo call, which means both IPv4 and IPv6 addresses will be searched simultaneously.<br>Libvalkey prefers IPv4 by default. |
| `VALKEY_OPT_PREFER_IPV4`<br>`VALKEY_OPT_PREFER_IPV6`<br>`VALKEY_OPT_PREFER_IP_UNSPEC` | Informs libvalkey to either prefer IPv4 or IPv6 when performing DNS resolution. `VALKEY_OPT_PREFER_IP_UNSPEC` will cause libvalkey to resolve both IPv4 and IPv6 addresses simultaneously.<br>Libvalkey prefers IPv4 by default. |
| `VALKEY_OPT_MPTCP` | Tells libvalkey to use multipath TCP (MPTCP). Note that only when both the server and client are using MPTCP do they establish an MPTCP connection between them; otherwise, they use a regular TCP connection instead. |

### Executing commands
Expand Down
8 changes: 7 additions & 1 deletion docs/standalone.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ When connecting to a server, libvalkey will return `NULL` in the event that we c

When a hostname resolves to multiple addresses, libvalkey will try each address in order until one succeeds or all have failed. Note that the `connect_timeout` applies per address, so the total connection time may be up to N × timeout when multiple addresses are unreachable.

#### DNS resolution with c-ares

When built with c-ares support (`USE_CARES=1` / `-DENABLE_CARES=1`), DNS resolution uses c-ares instead of `getaddrinfo()`. This provides timeout-bounded DNS resolution using `connect_timeout` (defaulting to 5 seconds if unset), preventing indefinite hangs when DNS servers are slow or unreachable.

c-ares support is available on Linux, macOS, and FreeBSD (not Windows).

```c
valkeyContext *ctx = valkeyConnect("localhost", 6379);
if (ctx == NULL || ctx->err) {
Expand Down Expand Up @@ -76,7 +82,7 @@ There are also several flags you can specify when using the `valkeyOptions` help
| --- | --- |
| `VALKEY_OPT_NONBLOCK` | Tells libvalkey to make a non-blocking connection. |
| `VALKEY_OPT_REUSEADDR` | Tells libvalkey to set the [SO_REUSEADDR](https://man7.org/linux/man-pages/man7/socket.7.html) socket option |
| `VALKEY_OPT_PREFER_IPV4`<br>`VALKEY_OPT_PREFER_IPV6`<br>`VALKEY_OPT_PREFER_IP_UNSPEC` | Informs libvalkey to either prefer IPv4 or IPv6 when invoking [getaddrinfo](https://man7.org/linux/man-pages/man3/gai_strerror.3.html). `VALKEY_OPT_PREFER_IP_UNSPEC` will cause libvalkey to specify `AF_UNSPEC` in the getaddrinfo call, which means both IPv4 and IPv6 addresses will be searched simultaneously.<br>Libvalkey prefers IPv4 by default. |
| `VALKEY_OPT_PREFER_IPV4`<br>`VALKEY_OPT_PREFER_IPV6`<br>`VALKEY_OPT_PREFER_IP_UNSPEC` | Informs libvalkey to either prefer IPv4 or IPv6 when performing DNS resolution. `VALKEY_OPT_PREFER_IP_UNSPEC` will resolve both IPv4 and IPv6 addresses simultaneously.<br>Libvalkey prefers IPv4 by default. |
| `VALKEY_OPT_NO_PUSH_AUTOFREE` | Tells libvalkey to not install the default RESP3 PUSH handler (which just intercepts and frees the replies). This is useful in situations where you want to process these messages in-band. |
| `VALKEY_OPT_NOAUTOFREEREPLIES` | **ASYNC**: tells libvalkey not to automatically invoke `freeReplyObject` after executing the reply callback. |
| `VALKEY_OPT_NOAUTOFREE` | **ASYNC**: Tells libvalkey not to automatically free the `valkeyAsyncContext` on connection/communication failure, but only if the user makes an explicit call to `valkeyAsyncDisconnect` or `valkeyAsyncFree` |
Expand Down
Loading
Loading