diff options
| -rw-r--r-- | async.c | 8 | ||||
| -rw-r--r-- | async.h | 2 | ||||
| -rw-r--r-- | hiredis.c | 9 | ||||
| -rw-r--r-- | hiredis.h | 12 | ||||
| -rw-r--r-- | net.c | 20 | 
5 files changed, 49 insertions, 2 deletions
| @@ -173,6 +173,14 @@ redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,      return ac;  } +redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, +                                                  const char *source_addr) { +    redisContext *c = redisConnectBindNonBlockWithReuse(ip,port,source_addr); +    redisAsyncContext *ac = redisAsyncInitialize(c); +    __redisAsyncCopyError(ac); +    return ac; +} +  redisAsyncContext *redisAsyncConnectUnix(const char *path) {      redisContext *c;      redisAsyncContext *ac; @@ -103,6 +103,8 @@ typedef struct redisAsyncContext {  /* Functions that proxy to hiredis */  redisAsyncContext *redisAsyncConnect(const char *ip, int port);  redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr); +redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, +                                                  const char *source_addr);  redisAsyncContext *redisAsyncConnectUnix(const char *path);  int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);  int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); @@ -1123,6 +1123,15 @@ redisContext *redisConnectBindNonBlock(const char *ip, int port,      return c;  } +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, +                                                const char *source_addr) { +    redisContext *c = redisContextInit(); +    c->flags &= ~REDIS_BLOCK; +    c->flags |= REDIS_REUSEADDR; +    redisContextConnectBindTcp(c,ip,port,NULL,source_addr); +    return c; +} +  redisContext *redisConnectUnix(const char *path) {      redisContext *c; @@ -80,6 +80,9 @@  /* 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 +  #define REDIS_REPLY_STRING 1  #define REDIS_REPLY_ARRAY 2  #define REDIS_REPLY_INTEGER 3 @@ -91,6 +94,10 @@  #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 +  #ifdef __cplusplus  extern "C" {  #endif @@ -177,7 +184,10 @@ typedef struct redisContext {  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 *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); @@ -256,10 +256,12 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {  static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,                                     const struct timeval *timeout,                                     const char *source_addr) { -    int s, rv; +    int s, rv, n;      char _port[6];  /* strlen("65535"); */      struct addrinfo hints, *servinfo, *bservinfo, *p, *b;      int blocking = (c->flags & REDIS_BLOCK); +    int reuseaddr = (c->flags & REDIS_REUSEADDR); +    int reuses = 0;      snprintf(_port, 6, "%d", port);      memset(&hints,0,sizeof(hints)); @@ -279,6 +281,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,          }      }      for (p = servinfo; p != NULL; p = p->ai_next) { +addrretry:          if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)              continue; @@ -294,6 +297,15 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,                  __redisSetError(c,REDIS_ERR_OTHER,buf);                  goto error;              } + +            if (reuseaddr) { +                n = 1; +                if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n, +                               sizeof(n)) < 0) { +                    goto error; +                } +            } +              for (b = bservinfo; b != NULL; b = b->ai_next) {                  if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {                      bound = 1; @@ -314,6 +326,12 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,                  continue;              } else if (errno == EINPROGRESS && !blocking) {                  /* This is ok. */ +            } else if (errno == EADDRNOTAVAIL && reuseaddr) { +                if (++reuses >= REDIS_CONNECT_RETRIES) { +                    goto error; +                } else { +                    goto addrretry; +                }              } else {                  if (redisContextWaitReady(c,timeout) != REDIS_OK)                      goto error; | 
