summaryrefslogtreecommitdiff
path: root/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'net.c')
-rw-r--r--net.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/net.c b/net.c
index be7a047..9718f76 100644
--- a/net.c
+++ b/net.c
@@ -47,6 +47,7 @@
#include <stdio.h>
#include <poll.h>
#include <limits.h>
+#include <stdlib.h>
#include "net.h"
#include "sds.h"
@@ -263,6 +264,44 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
int reuseaddr = (c->flags & REDIS_REUSEADDR);
int reuses = 0;
+ c->connection_type = REDIS_CONN_TCP;
+ c->tcp.port = port;
+
+ /* We need to take possession of the passed parameters
+ * to make them reusable for a reconnect.
+ * We also carefully check we don't free data we already own,
+ * as in the case of the reconnect method.
+ *
+ * This is a bit ugly, but atleast it works and doesn't leak memory.
+ **/
+ if (c->tcp.host != addr) {
+ if (c->tcp.host)
+ free(c->tcp.host);
+
+ c->tcp.host = strdup(addr);
+ }
+
+ if (timeout) {
+ if (c->timeout != timeout) {
+ if (c->timeout == NULL)
+ c->timeout = malloc(sizeof(struct timeval));
+
+ memcpy(c->timeout, timeout, sizeof(struct timeval));
+ }
+ } else {
+ if (c->timeout)
+ free(c->timeout);
+ c->timeout = NULL;
+ }
+
+ if (source_addr == NULL) {
+ free(c->tcp.source_addr);
+ c->tcp.source_addr = NULL;
+ } else if (c->tcp.source_addr != source_addr) {
+ free(c->tcp.source_addr);
+ c->tcp.source_addr = strdup(source_addr);
+ }
+
snprintf(_port, 6, "%d", port);
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_INET;
@@ -273,7 +312,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
* 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(addr,_port,&hints,&servinfo)) != 0) {
+ 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));
@@ -288,10 +327,10 @@ addrretry:
c->fd = s;
if (redisSetBlocking(c,0) != REDIS_OK)
goto error;
- if (source_addr) {
+ if (c->tcp.source_addr) {
int bound = 0;
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
- if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) {
+ if ((rv = getaddrinfo(c->tcp.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);
@@ -333,7 +372,7 @@ addrretry:
goto addrretry;
}
} else {
- if (redisContextWaitReady(c,timeout) != REDIS_OK)
+ if (redisContextWaitReady(c,c->timeout) != REDIS_OK)
goto error;
}
}
@@ -380,13 +419,30 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time
if (redisSetBlocking(c,0) != REDIS_OK)
return REDIS_ERR;
+ c->connection_type = REDIS_CONN_UNIX;
+ if (c->unix.path != path)
+ c->unix.path = strdup(path);
+
+ if (timeout) {
+ if (c->timeout != timeout) {
+ if (c->timeout == NULL)
+ c->timeout = malloc(sizeof(struct timeval));
+
+ memcpy(c->timeout, timeout, sizeof(struct timeval));
+ }
+ } else {
+ if (c->timeout)
+ free(c->timeout);
+ c->timeout = NULL;
+ }
+
sa.sun_family = AF_LOCAL;
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
if (errno == EINPROGRESS && !blocking) {
/* This is ok. */
} else {
- if (redisContextWaitReady(c,timeout) != REDIS_OK)
+ if (redisContextWaitReady(c,c->timeout) != REDIS_OK)
return REDIS_ERR;
}
}