Commit 1bcf4024 authored by michael-grunder's avatar michael-grunder
Browse files

Add a user-defined callback to set custom socket options.

Fixes #698
parent 855b48a8
...@@ -829,6 +829,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) { ...@@ -829,6 +829,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
c->flags |= REDIS_PREFER_IPV6; c->flags |= REDIS_PREFER_IPV6;
} }
/* Set any configured socket callback function */
c->socket_cb = options->socket_cb;
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject /* Set any user supplied RESP3 PUSH handler or use freeReplyObject
* as a default unless specifically flagged that we don't want one. */ * as a default unless specifically flagged that we don't want one. */
if (options->push_cb != NULL) if (options->push_cb != NULL)
......
...@@ -216,6 +216,10 @@ typedef struct { ...@@ -216,6 +216,10 @@ typedef struct {
redisFD fd; redisFD fd;
} endpoint; } endpoint;
/* Socket callback function executed after socket creation but before
* we connect. This can be used to set OS specific socket options. */
int (*socket_cb)(redisFD fd, void *privdata, char **errstr);
/* Optional user defined data/destructor */ /* Optional user defined data/destructor */
void *privdata; void *privdata;
void (*free_privdata)(void *); void (*free_privdata)(void *);
...@@ -239,6 +243,10 @@ typedef struct { ...@@ -239,6 +243,10 @@ typedef struct {
(opts)->endpoint.unix_socket = path; \ (opts)->endpoint.unix_socket = path; \
} while(0) } while(0)
#define REDIS_OPTIONS_SET_SOCKET_CB(opts, cb) do { \
(opts)->socket_cb = cb; \
} while(0)
#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) do { \ #define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) do { \
(opts)->privdata = data; \ (opts)->privdata = data; \
(opts)->free_privdata = dtor; \ (opts)->free_privdata = dtor; \
...@@ -288,6 +296,11 @@ typedef struct redisContext { ...@@ -288,6 +296,11 @@ typedef struct redisContext {
struct sockaddr *saddr; struct sockaddr *saddr;
size_t addrlen; size_t addrlen;
/* A callback to be invoked after successful socket creation but before we
* connect. This can be usefull for setting OS specific socket flags.
* The callback may optionally set errstr in the event of an error. */
int (*socket_cb)(redisFD fd, void *privdata, char **errstr);
/* Optional data and corresponding destructor users can use to provide /* Optional data and corresponding destructor users can use to provide
* context to a given redisContext. Not used by hiredis. */ * context to a given redisContext. Not used by hiredis. */
void *privdata; void *privdata;
......
...@@ -402,6 +402,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, ...@@ -402,6 +402,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
int rv, n; int rv, n;
char _port[6]; /* strlen("65535"); */ char _port[6]; /* strlen("65535"); */
struct addrinfo hints, *servinfo, *bservinfo, *p, *b; struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
char *errstr;
int blocking = (c->flags & REDIS_BLOCK); int blocking = (c->flags & REDIS_BLOCK);
int reuseaddr = (c->flags & REDIS_REUSEADDR); int reuseaddr = (c->flags & REDIS_REUSEADDR);
int reuses = 0; int reuses = 0;
...@@ -477,6 +478,13 @@ addrretry: ...@@ -477,6 +478,13 @@ addrretry:
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD) if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD)
continue; continue;
/* Invoke any user-provided socket callback */
errstr = NULL;
if (c->socket_cb && c->socket_cb(s, c->privdata, &errstr) != REDIS_OK) {
__redisSetError(c, REDIS_ERR_OTHER, errstr ? errstr : "Failure in user-defined socket callback");
goto error;
}
c->fd = s; c->fd = s;
if (redisSetBlocking(c,0) != REDIS_OK) if (redisSetBlocking(c,0) != REDIS_OK)
goto error; goto error;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment