diff options
author | Viktor Söderqvist <viktor.soderqvist@est.tech> | 2022-09-01 12:04:59 +0200 |
---|---|---|
committer | Michael Grunder <michael.grunder@gmail.com> | 2022-09-01 10:42:36 -0700 |
commit | 10c78c6e179a32b3e1f9cd99bf18dcf0c37d295e (patch) | |
tree | 36ea03abf4c9351a374e92a201c3c8cdc60788a3 | |
parent | 1abe0c8285100e31a4688b3b09023eb3ad942394 (diff) |
Add possibility to prefer IPv6, IPv4 or unspecified
-rw-r--r-- | hiredis.c | 6 | ||||
-rw-r--r-- | hiredis.h | 7 | ||||
-rw-r--r-- | net.c | 30 |
3 files changed, 32 insertions, 11 deletions
@@ -814,6 +814,12 @@ redisContext *redisConnectWithOptions(const redisOptions *options) { 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. */ @@ -92,6 +92,11 @@ typedef long long ssize_t; /* 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 @@ -149,6 +154,8 @@ struct redisSsl; #define REDIS_OPT_NONBLOCK 0x01 #define REDIS_OPT_REUSEADDR 0x02 +#define REDIS_OPT_PREFER_IPV4 0x04 +#define REDIS_OPT_PREFER_IPV6 0x08 /** * Don't automatically free the async object on a connection failure, @@ -439,17 +439,25 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; - /* Try with IPv6 if no IPv4 address was found. We do it in this order since - * in a Redis client you can't afford to test if you have IPv6 connectivity - * as this would add latency to every connect. Otherwise a more sensible - * route could be: Use IPv6 if both addresses are available and there is IPv6 - * connectivity. */ - if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) { - hints.ai_family = AF_INET6; - if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) { - __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv)); - return REDIS_ERR; - } + /* DNS lookup. To use dual stack, set both flags to prefer both IPv4 and + * IPv6. By default, for historical reasons, we try IPv4 first and then we + * try IPv6 only if no IPv4 address was found. */ + if (c->flags & REDIS_PREFER_IPV6 && c->flags & REDIS_PREFER_IPV4) + hints.ai_family = AF_UNSPEC; + else if (c->flags & REDIS_PREFER_IPV6) + hints.ai_family = AF_INET6; + else + hints.ai_family = AF_INET; + + rv = getaddrinfo(c->tcp.host, _port, &hints, &servinfo); + if (rv != 0 && hints.ai_family != AF_UNSPEC) { + /* Try again with the other IP version. */ + hints.ai_family = (hints.ai_family == AF_INET) ? AF_INET6 : AF_INET; + rv = getaddrinfo(c->tcp.host, _port, &hints, &servinfo); + } + if (rv != 0) { + __redisSetError(c, REDIS_ERR_OTHER, gai_strerror(rv)); + return REDIS_ERR; } for (p = servinfo; p != NULL; p = p->ai_next) { addrretry: |