diff options
| -rw-r--r-- | async.c | 8 | ||||
| -rw-r--r-- | async.h | 1 | ||||
| -rw-r--r-- | hiredis.c | 8 | ||||
| -rw-r--r-- | hiredis.h | 1 | ||||
| -rw-r--r-- | net.c | 38 | ||||
| -rw-r--r-- | net.h | 2 | 
6 files changed, 56 insertions, 2 deletions
@@ -165,6 +165,14 @@ redisAsyncContext *redisAsyncConnect(const char *ip, int port) {      return ac;  } +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, +                                         char *source_addr) { +    redisContext *c = redisConnectBindNonBlock(ip,port,source_addr); +    redisAsyncContext *ac = redisAsyncInitialize(c); +    __redisAsyncCopyError(ac); +    return ac; +} +  redisAsyncContext *redisAsyncConnectUnix(const char *path) {      redisContext *c;      redisAsyncContext *ac; @@ -102,6 +102,7 @@ typedef struct redisAsyncContext {  /* Functions that proxy to hiredis */  redisAsyncContext *redisAsyncConnect(const char *ip, int port); +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,char *source);  redisAsyncContext *redisAsyncConnectUnix(const char *path);  int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);  int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); @@ -1049,6 +1049,14 @@ redisContext *redisConnectNonBlock(const char *ip, int port) {      return c;  } +redisContext *redisConnectBindNonBlock(const char *ip, int port, +                                   char *source_addr) { +    redisContext *c = redisContextInit(); +    c->flags &= ~REDIS_BLOCK; +    redisContextConnectBindTcp(c,ip,port,NULL,source_addr); +    return c; +} +  redisContext *redisConnectUnix(const char *path) {      redisContext *c; @@ -175,6 +175,7 @@ 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, char *source);  redisContext *redisConnectUnix(const char *path);  redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);  redisContext *redisConnectUnixNonBlock(const char *path); @@ -250,10 +250,12 @@ int redisContextSetTimeout(redisContext *c, const struct timeval tv) {      return REDIS_OK;  } -int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout) { +static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, +                                   const struct timeval *timeout, +                                   char *source_addr) {      int s, rv;      char _port[6];  /* strlen("65535"); */ -    struct addrinfo hints, *servinfo, *p; +    struct addrinfo hints, *servinfo, *bservinfo, *p, *b;      int blocking = (c->flags & REDIS_BLOCK);      snprintf(_port, 6, "%d", port); @@ -280,6 +282,28 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, const st          c->fd = s;          if (redisSetBlocking(c,0) != REDIS_OK)              goto error; +        if (source_addr) { +            int bound = 0; +            /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ +            if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) { +                char buf[128]; +                snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv)); +                __redisSetError(c,REDIS_ERR_OTHER,buf); +                goto error; +            } +            for (b = bservinfo; b != NULL; b = b->ai_next) { +                if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { +                    bound = 1; +                    break; +                } +            } +            if (!bound) { +                char buf[128]; +                snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno)); +                __redisSetError(c,REDIS_ERR_OTHER,buf); +                goto error; +            } +        }          if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {              if (errno == EHOSTUNREACH) {                  redisContextCloseFd(c); @@ -314,6 +338,16 @@ end:      return rv;  // Need to return REDIS_OK if alright  } +int redisContextConnectTcp(redisContext *c, const char *addr, int port, +                           const struct timeval *timeout) { +    return _redisContextConnectTcp(c, addr, port, timeout, NULL); +} + +int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, +                               const struct timeval *timeout, char *source_addr) { +    return _redisContextConnectTcp(c, addr, port, timeout, source_addr); +} +  int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {      int blocking = (c->flags & REDIS_BLOCK);      struct sockaddr_un sa; @@ -42,6 +42,8 @@  int redisCheckSocketError(redisContext *c);  int redisContextSetTimeout(redisContext *c, const struct timeval tv);  int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); +int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, +                               const struct timeval *timeout, char *source_addr);  int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);  int redisKeepAlive(redisContext *c, int interval);  | 
