Compare commits
5 Commits
ca4a0e850b
...
61b5b299f0
Author | SHA1 | Date |
---|---|---|
Michael Grunder | 61b5b299f0 | |
zhenwei pi | fce8abc1c1 | |
Michael Grunder | cfb6ca8811 | |
michael-grunder | cc7c35ce60 | |
zhangtaoXT5 | bc8d837b72 |
35
README.md
35
README.md
|
@ -82,6 +82,7 @@ an error state. The field `errstr` will contain a string with a description of
|
|||
the error. More information on errors can be found in the **Errors** section.
|
||||
After trying to connect to Redis using `redisConnect` you should
|
||||
check the `err` field to see if establishing the connection was successful:
|
||||
|
||||
```c
|
||||
redisContext *c = redisConnect("127.0.0.1", 6379);
|
||||
if (c == NULL || c->err) {
|
||||
|
@ -94,6 +95,40 @@ if (c == NULL || c->err) {
|
|||
}
|
||||
```
|
||||
|
||||
One can also use `redisConnectWithOptions` which takes a `redisOptions` argument
|
||||
that can be configured with endpoint information as well as many different flags
|
||||
to change how the `redisContext` will be configured.
|
||||
|
||||
```c
|
||||
redisOptions opt = {0};
|
||||
|
||||
/* One can set the endpoint with one of our helper macros */
|
||||
if (tcp) {
|
||||
REDIS_OPTIONS_SET_TCP(&opt, "localhost", 6379);
|
||||
} else {
|
||||
REDIS_OPTIONS_SET_UNIX(&opt, "/tmp/redis.sock");
|
||||
}
|
||||
|
||||
/* And privdata can be specified with another helper */
|
||||
REDIS_OPTIONS_SET_PRIVDATA(&opt, myPrivData, myPrivDataDtor);
|
||||
|
||||
/* Finally various options may be set via the `options` member, as described below */
|
||||
opt->options |= REDIS_OPT_PREFER_IPV4;
|
||||
```
|
||||
|
||||
### Configurable redisOptions flags
|
||||
|
||||
There are several flags you may set in the `redisOptions` struct to change default behavior. You can specify the flags via the `redisOptions->options` member.
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| REDIS\_OPT\_NONBLOCK | Tells hiredis to make a non-blocking connection. |
|
||||
| REDIS\_OPT\_REUSEADDR | Tells hiredis to set the [SO_REUSEADDR](https://man7.org/linux/man-pages/man7/socket.7.html) socket option |
|
||||
| REDIS\_OPT\_PREFER\_IPV4<br>REDIS\_OPT\_PREFER_IPV6<br>REDIS\_OPT\_PREFER\_IP\_UNSPEC | Informs hiredis to either prefer IPv4 or IPv6 when invoking [getaddrinfo](https://man7.org/linux/man-pages/man3/gai_strerror.3.html). `REDIS_OPT_PREFER_IP_UNSPEC` will cause hiredis to specify `AF_UNSPEC` in the getaddrinfo call, which means both IPv4 and IPv6 addresses will be searched simultaneously.<br>Hiredis prefers IPv4 by default. |
|
||||
| REDIS\_OPT\_NO\_PUSH\_AUTOFREE | Tells hiredis 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. |
|
||||
| REDIS\_OPT\_NOAUOTFREEREPLIES | **ASYNC**: tells hiredis not to automatically invoke `freeReplyObject` after executing the reply callback. |
|
||||
| REDIS\_OPT\_NOAUTOFREE | **ASYNC**: Tells hiredis not to automatically free the `redisAsyncContext` on connection/communication failure, but only if the user makes an explicit call to `redisAsyncDisconnect` or `redisAsyncFree` |
|
||||
|
||||
*Note: A `redisContext` is not thread-safe.*
|
||||
|
||||
### Sending commands
|
||||
|
|
12
hiredis.c
12
hiredis.c
|
@ -48,6 +48,7 @@ extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeva
|
|||
extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout);
|
||||
|
||||
static redisContextFuncs redisContextDefaultFuncs = {
|
||||
.close = redisNetClose,
|
||||
.free_privctx = NULL,
|
||||
.async_read = redisAsyncRead,
|
||||
.async_write = redisAsyncWrite,
|
||||
|
@ -485,6 +486,8 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
|
|||
|
||||
touched = 1;
|
||||
c++;
|
||||
if (*c == '\0')
|
||||
break;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
@ -727,7 +730,10 @@ static redisContext *redisContextInit(void) {
|
|||
void redisFree(redisContext *c) {
|
||||
if (c == NULL)
|
||||
return;
|
||||
redisNetClose(c);
|
||||
|
||||
if (c->funcs && c->funcs->close) {
|
||||
c->funcs->close(c);
|
||||
}
|
||||
|
||||
sdsfree(c->obuf);
|
||||
redisReaderFree(c->reader);
|
||||
|
@ -764,7 +770,9 @@ int redisReconnect(redisContext *c) {
|
|||
c->privctx = NULL;
|
||||
}
|
||||
|
||||
redisNetClose(c);
|
||||
if (c->funcs && c->funcs->close) {
|
||||
c->funcs->close(c);
|
||||
}
|
||||
|
||||
sdsfree(c->obuf);
|
||||
redisReaderFree(c->reader);
|
||||
|
|
|
@ -156,6 +156,7 @@ struct redisSsl;
|
|||
#define REDIS_OPT_REUSEADDR 0x02
|
||||
#define REDIS_OPT_PREFER_IPV4 0x04
|
||||
#define REDIS_OPT_PREFER_IPV6 0x08
|
||||
#define REDIS_OPT_PREFER_IP_UNSPEC (REDIS_OPT_PREFER_IPV4 | REDIS_OPT_PREFER_IPV6)
|
||||
|
||||
/**
|
||||
* Don't automatically free the async object on a connection failure,
|
||||
|
@ -244,6 +245,7 @@ typedef struct {
|
|||
} while(0)
|
||||
|
||||
typedef struct redisContextFuncs {
|
||||
void (*close)(struct redisContext *);
|
||||
void (*free_privctx)(void *);
|
||||
void (*async_read)(struct redisAsyncContext *);
|
||||
void (*async_write)(struct redisAsyncContext *);
|
||||
|
|
9
net.c
9
net.c
|
@ -168,6 +168,7 @@ int redisKeepAlive(redisContext *c, int interval) {
|
|||
int val = 1;
|
||||
redisFD fd = c->fd;
|
||||
|
||||
#ifndef _WIN32
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
|
||||
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
||||
return REDIS_ERR;
|
||||
|
@ -201,7 +202,15 @@ int redisKeepAlive(redisContext *c, int interval) {
|
|||
}
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
int res;
|
||||
|
||||
res = win32_redisKeepAlive(fd, interval * 1000);
|
||||
if (res != 0) {
|
||||
__redisSetError(c, REDIS_ERR_OTHER, strerror(res));
|
||||
return REDIS_ERR;
|
||||
}
|
||||
#endif
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
|
|
17
sockcompat.c
17
sockcompat.c
|
@ -260,4 +260,21 @@ int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
|||
_updateErrno(ret != SOCKET_ERROR);
|
||||
return ret != SOCKET_ERROR ? ret : -1;
|
||||
}
|
||||
|
||||
int win32_redisKeepAlive(SOCKET sockfd, int interval_ms) {
|
||||
struct tcp_keepalive cfg;
|
||||
DWORD bytes_in;
|
||||
int res;
|
||||
|
||||
cfg.onoff = 1;
|
||||
cfg.keepaliveinterval = interval_ms;
|
||||
cfg.keepalivetime = interval_ms;
|
||||
|
||||
res = WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, &cfg,
|
||||
sizeof(struct tcp_keepalive), NULL, 0,
|
||||
&bytes_in, NULL, NULL);
|
||||
|
||||
return res == 0 ? 0 : _wsaErrorToErrno(res);
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <ws2tcpip.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <Mstcpip.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef long long ssize_t;
|
||||
|
@ -71,6 +72,8 @@ ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
|
|||
typedef ULONG nfds_t;
|
||||
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
int win32_redisKeepAlive(SOCKET sockfd, int interval_ms);
|
||||
|
||||
#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
|
||||
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
|
||||
#undef gai_strerror
|
||||
|
|
2
ssl.c
2
ssl.c
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "hiredis.h"
|
||||
#include "async.h"
|
||||
#include "net.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
@ -579,6 +580,7 @@ static void redisSSLAsyncWrite(redisAsyncContext *ac) {
|
|||
}
|
||||
|
||||
redisContextFuncs redisContextSSLFuncs = {
|
||||
.close = redisNetClose,
|
||||
.free_privctx = redisSSLFree,
|
||||
.async_read = redisSSLAsyncRead,
|
||||
.async_write = redisSSLAsyncWrite,
|
||||
|
|
11
test.c
11
test.c
|
@ -405,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
|
|||
disconnect(c, 0);
|
||||
}
|
||||
|
||||
static void test_tcp_options(struct config cfg) {
|
||||
redisContext *c;
|
||||
|
||||
c = do_connect(cfg);
|
||||
test("We can enable TCP_KEEPALIVE: ");
|
||||
test_cond(redisEnableKeepAlive(c) == REDIS_OK);
|
||||
|
||||
disconnect(c, 0);
|
||||
}
|
||||
|
||||
static void test_reply_reader(void) {
|
||||
redisReader *reader;
|
||||
void *reply, *root;
|
||||
|
@ -2261,6 +2271,7 @@ int main(int argc, char **argv) {
|
|||
test_blocking_io_errors(cfg);
|
||||
test_invalid_timeout_errors(cfg);
|
||||
test_append_formatted_commands(cfg);
|
||||
test_tcp_options(cfg);
|
||||
if (throughput) test_throughput(cfg);
|
||||
|
||||
printf("\nTesting against Unix socket connection (%s): ", cfg.unix_sock.path);
|
||||
|
|
Loading…
Reference in New Issue