hiredis 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/ext/hiredis_ext/connection.c +4 -3
- data/ext/hiredis_ext/reader.c +12 -6
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/Makefile +53 -34
- data/vendor/hiredis/async.c +40 -9
- data/vendor/hiredis/async.h +1 -0
- data/vendor/hiredis/dict.c +2 -2
- data/vendor/hiredis/fmacros.h +4 -13
- data/vendor/hiredis/hiredis.c +50 -23
- data/vendor/hiredis/hiredis.h +37 -27
- data/vendor/hiredis/net.c +99 -22
- data/vendor/hiredis/net.h +4 -6
- data/vendor/hiredis/read.c +119 -44
- data/vendor/hiredis/read.h +4 -9
- data/vendor/hiredis/sds.c +342 -165
- data/vendor/hiredis/sds.h +184 -13
- data/vendor/hiredis/sdsalloc.h +42 -0
- data/vendor/hiredis/test.c +187 -14
- data/vendor/hiredis/win32.h +42 -0
- metadata +5 -3
data/vendor/hiredis/hiredis.c
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
/*
|
2
2
|
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
3
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
4
|
+
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
5
|
+
* Jan-Erik Rediger <janerik at fnordig dot com>
|
4
6
|
*
|
5
7
|
* All rights reserved.
|
6
8
|
*
|
@@ -82,16 +84,14 @@ void freeReplyObject(void *reply) {
|
|
82
84
|
case REDIS_REPLY_ARRAY:
|
83
85
|
if (r->element != NULL) {
|
84
86
|
for (j = 0; j < r->elements; j++)
|
85
|
-
|
86
|
-
freeReplyObject(r->element[j]);
|
87
|
+
freeReplyObject(r->element[j]);
|
87
88
|
free(r->element);
|
88
89
|
}
|
89
90
|
break;
|
90
91
|
case REDIS_REPLY_ERROR:
|
91
92
|
case REDIS_REPLY_STATUS:
|
92
93
|
case REDIS_REPLY_STRING:
|
93
|
-
|
94
|
-
free(r->str);
|
94
|
+
free(r->str);
|
95
95
|
break;
|
96
96
|
}
|
97
97
|
free(r);
|
@@ -430,11 +430,7 @@ cleanup:
|
|
430
430
|
}
|
431
431
|
|
432
432
|
sdsfree(curarg);
|
433
|
-
|
434
|
-
/* No need to check cmd since it is the last statement that can fail,
|
435
|
-
* but do it anyway to be as defensive as possible. */
|
436
|
-
if (cmd != NULL)
|
437
|
-
free(cmd);
|
433
|
+
free(cmd);
|
438
434
|
|
439
435
|
return error_type;
|
440
436
|
}
|
@@ -505,7 +501,7 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
|
|
505
501
|
cmd = sdscatfmt(cmd, "*%i\r\n", argc);
|
506
502
|
for (j=0; j < argc; j++) {
|
507
503
|
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
508
|
-
cmd = sdscatfmt(cmd, "$%
|
504
|
+
cmd = sdscatfmt(cmd, "$%u\r\n", len);
|
509
505
|
cmd = sdscatlen(cmd, argv[j], len);
|
510
506
|
cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
|
511
507
|
}
|
@@ -579,7 +575,7 @@ void __redisSetError(redisContext *c, int type, const char *str) {
|
|
579
575
|
} else {
|
580
576
|
/* Only REDIS_ERR_IO may lack a description! */
|
581
577
|
assert(type == REDIS_ERR_IO);
|
582
|
-
|
578
|
+
strerror_r(errno, c->errstr, sizeof(c->errstr));
|
583
579
|
}
|
584
580
|
}
|
585
581
|
|
@@ -594,8 +590,6 @@ static redisContext *redisContextInit(void) {
|
|
594
590
|
if (c == NULL)
|
595
591
|
return NULL;
|
596
592
|
|
597
|
-
c->err = 0;
|
598
|
-
c->errstr[0] = '\0';
|
599
593
|
c->obuf = sdsempty();
|
600
594
|
c->reader = redisReaderCreate();
|
601
595
|
|
@@ -612,10 +606,12 @@ void redisFree(redisContext *c) {
|
|
612
606
|
return;
|
613
607
|
if (c->fd > 0)
|
614
608
|
close(c->fd);
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
609
|
+
sdsfree(c->obuf);
|
610
|
+
redisReaderFree(c->reader);
|
611
|
+
free(c->tcp.host);
|
612
|
+
free(c->tcp.source_addr);
|
613
|
+
free(c->unix_sock.path);
|
614
|
+
free(c->timeout);
|
619
615
|
free(c);
|
620
616
|
}
|
621
617
|
|
@@ -626,6 +622,34 @@ int redisFreeKeepFd(redisContext *c) {
|
|
626
622
|
return fd;
|
627
623
|
}
|
628
624
|
|
625
|
+
int redisReconnect(redisContext *c) {
|
626
|
+
c->err = 0;
|
627
|
+
memset(c->errstr, '\0', strlen(c->errstr));
|
628
|
+
|
629
|
+
if (c->fd > 0) {
|
630
|
+
close(c->fd);
|
631
|
+
}
|
632
|
+
|
633
|
+
sdsfree(c->obuf);
|
634
|
+
redisReaderFree(c->reader);
|
635
|
+
|
636
|
+
c->obuf = sdsempty();
|
637
|
+
c->reader = redisReaderCreate();
|
638
|
+
|
639
|
+
if (c->connection_type == REDIS_CONN_TCP) {
|
640
|
+
return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
|
641
|
+
c->timeout, c->tcp.source_addr);
|
642
|
+
} else if (c->connection_type == REDIS_CONN_UNIX) {
|
643
|
+
return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
|
644
|
+
} else {
|
645
|
+
/* Something bad happened here and shouldn't have. There isn't
|
646
|
+
enough information in the context to reconnect. */
|
647
|
+
__redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
|
648
|
+
}
|
649
|
+
|
650
|
+
return REDIS_ERR;
|
651
|
+
}
|
652
|
+
|
629
653
|
/* Connect to a Redis instance. On error the field error in the returned
|
630
654
|
* context will be set to the return value of the error function.
|
631
655
|
* When no set of reply functions is given, the default set will be used. */
|
@@ -668,6 +692,8 @@ redisContext *redisConnectNonBlock(const char *ip, int port) {
|
|
668
692
|
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
669
693
|
const char *source_addr) {
|
670
694
|
redisContext *c = redisContextInit();
|
695
|
+
if (c == NULL)
|
696
|
+
return NULL;
|
671
697
|
c->flags &= ~REDIS_BLOCK;
|
672
698
|
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
|
673
699
|
return c;
|
@@ -676,6 +702,8 @@ redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
|
676
702
|
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
677
703
|
const char *source_addr) {
|
678
704
|
redisContext *c = redisContextInit();
|
705
|
+
if (c == NULL)
|
706
|
+
return NULL;
|
679
707
|
c->flags &= ~REDIS_BLOCK;
|
680
708
|
c->flags |= REDIS_REUSEADDR;
|
681
709
|
redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
|
@@ -780,10 +808,10 @@ int redisBufferRead(redisContext *c) {
|
|
780
808
|
/* Write the output buffer to the socket.
|
781
809
|
*
|
782
810
|
* Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
|
783
|
-
*
|
811
|
+
* successfully written to the socket. When the buffer is empty after the
|
784
812
|
* write operation, "done" is set to 1 (if given).
|
785
813
|
*
|
786
|
-
* Returns REDIS_ERR if an error
|
814
|
+
* Returns REDIS_ERR if an error occurred trying to write and sets
|
787
815
|
* c->errstr to hold the appropriate error string.
|
788
816
|
*/
|
789
817
|
int redisBufferWrite(redisContext *c, int *done) {
|
@@ -942,7 +970,7 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
|
|
942
970
|
* context is non-blocking, the "reply" pointer will not be used and the
|
943
971
|
* command is simply appended to the write buffer.
|
944
972
|
*
|
945
|
-
* Returns the reply when a reply was
|
973
|
+
* Returns the reply when a reply was successfully retrieved. Returns NULL
|
946
974
|
* otherwise. When NULL is returned in a blocking context, the error field
|
947
975
|
* in the context will be set.
|
948
976
|
*/
|
@@ -965,9 +993,8 @@ void *redisvCommand(redisContext *c, const char *format, va_list ap) {
|
|
965
993
|
|
966
994
|
void *redisCommand(redisContext *c, const char *format, ...) {
|
967
995
|
va_list ap;
|
968
|
-
void *reply = NULL;
|
969
996
|
va_start(ap,format);
|
970
|
-
reply = redisvCommand(c,format,ap);
|
997
|
+
void *reply = redisvCommand(c,format,ap);
|
971
998
|
va_end(ap);
|
972
999
|
return reply;
|
973
1000
|
}
|
data/vendor/hiredis/hiredis.h
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
/*
|
2
2
|
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
3
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
4
|
+
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
5
|
+
* Jan-Erik Rediger <janerik at fnordig dot com>
|
4
6
|
*
|
5
7
|
* All rights reserved.
|
6
8
|
*
|
@@ -38,8 +40,9 @@
|
|
38
40
|
#include "sds.h" /* for sds */
|
39
41
|
|
40
42
|
#define HIREDIS_MAJOR 0
|
41
|
-
#define HIREDIS_MINOR
|
43
|
+
#define HIREDIS_MINOR 14
|
42
44
|
#define HIREDIS_PATCH 0
|
45
|
+
#define HIREDIS_SONAME 0.14
|
43
46
|
|
44
47
|
/* Connection type can be blocking or non-blocking and is set in the
|
45
48
|
* least significant bit of the flags field in redisContext. */
|
@@ -77,30 +80,6 @@
|
|
77
80
|
* SO_REUSEADDR is being used. */
|
78
81
|
#define REDIS_CONNECT_RETRIES 10
|
79
82
|
|
80
|
-
/* strerror_r has two completely different prototypes and behaviors
|
81
|
-
* depending on system issues, so we need to operate on the error buffer
|
82
|
-
* differently depending on which strerror_r we're using. */
|
83
|
-
#ifndef _GNU_SOURCE
|
84
|
-
/* "regular" POSIX strerror_r that does the right thing. */
|
85
|
-
#define __redis_strerror_r(errno, buf, len) \
|
86
|
-
do { \
|
87
|
-
strerror_r((errno), (buf), (len)); \
|
88
|
-
} while (0)
|
89
|
-
#else
|
90
|
-
/* "bad" GNU strerror_r we need to clean up after. */
|
91
|
-
#define __redis_strerror_r(errno, buf, len) \
|
92
|
-
do { \
|
93
|
-
char *err_str = strerror_r((errno), (buf), (len)); \
|
94
|
-
/* If return value _isn't_ the start of the buffer we passed in, \
|
95
|
-
* then GNU strerror_r returned an internal static buffer and we \
|
96
|
-
* need to copy the result into our private buffer. */ \
|
97
|
-
if (err_str != (buf)) { \
|
98
|
-
buf[(len)] = '\0'; \
|
99
|
-
strncat((buf), err_str, ((len) - 1)); \
|
100
|
-
} \
|
101
|
-
} while (0)
|
102
|
-
#endif
|
103
|
-
|
104
83
|
#ifdef __cplusplus
|
105
84
|
extern "C" {
|
106
85
|
#endif
|
@@ -109,7 +88,7 @@ extern "C" {
|
|
109
88
|
typedef struct redisReply {
|
110
89
|
int type; /* REDIS_REPLY_* */
|
111
90
|
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
|
112
|
-
|
91
|
+
size_t len; /* Length of string */
|
113
92
|
char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
|
114
93
|
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
|
115
94
|
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
|
@@ -128,6 +107,11 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const s
|
|
128
107
|
void redisFreeCommand(char *cmd);
|
129
108
|
void redisFreeSdsCommand(sds cmd);
|
130
109
|
|
110
|
+
enum redisConnectionType {
|
111
|
+
REDIS_CONN_TCP,
|
112
|
+
REDIS_CONN_UNIX
|
113
|
+
};
|
114
|
+
|
131
115
|
/* Context for a connection to Redis */
|
132
116
|
typedef struct redisContext {
|
133
117
|
int err; /* Error flags, 0 when there is no error */
|
@@ -136,6 +120,20 @@ typedef struct redisContext {
|
|
136
120
|
int flags;
|
137
121
|
char *obuf; /* Write buffer */
|
138
122
|
redisReader *reader; /* Protocol reader */
|
123
|
+
|
124
|
+
enum redisConnectionType connection_type;
|
125
|
+
struct timeval *timeout;
|
126
|
+
|
127
|
+
struct {
|
128
|
+
char *host;
|
129
|
+
char *source_addr;
|
130
|
+
int port;
|
131
|
+
} tcp;
|
132
|
+
|
133
|
+
struct {
|
134
|
+
char *path;
|
135
|
+
} unix_sock;
|
136
|
+
|
139
137
|
} redisContext;
|
140
138
|
|
141
139
|
redisContext *redisConnect(const char *ip, int port);
|
@@ -149,6 +147,18 @@ redisContext *redisConnectUnix(const char *path);
|
|
149
147
|
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
150
148
|
redisContext *redisConnectUnixNonBlock(const char *path);
|
151
149
|
redisContext *redisConnectFd(int fd);
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Reconnect the given context using the saved information.
|
153
|
+
*
|
154
|
+
* This re-uses the exact same connect options as in the initial connection.
|
155
|
+
* host, ip (or path), timeout and bind address are reused,
|
156
|
+
* flags are used unmodified from the existing context.
|
157
|
+
*
|
158
|
+
* Returns REDIS_OK on successful connect or REDIS_ERR otherwise.
|
159
|
+
*/
|
160
|
+
int redisReconnect(redisContext *c);
|
161
|
+
|
152
162
|
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
153
163
|
int redisEnableKeepAlive(redisContext *c);
|
154
164
|
void redisFree(redisContext *c);
|
data/vendor/hiredis/net.c
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
2
2
|
*
|
3
|
-
* Copyright (c)
|
4
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
5
|
+
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
6
|
+
* Jan-Erik Rediger <janerik at fnordig dot com>
|
5
7
|
*
|
6
8
|
* All rights reserved.
|
7
9
|
*
|
@@ -47,6 +49,7 @@
|
|
47
49
|
#include <stdio.h>
|
48
50
|
#include <poll.h>
|
49
51
|
#include <limits.h>
|
52
|
+
#include <stdlib.h>
|
50
53
|
|
51
54
|
#include "net.h"
|
52
55
|
#include "sds.h"
|
@@ -62,12 +65,13 @@ static void redisContextCloseFd(redisContext *c) {
|
|
62
65
|
}
|
63
66
|
|
64
67
|
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
|
68
|
+
int errorno = errno; /* snprintf() may change errno */
|
65
69
|
char buf[128] = { 0 };
|
66
70
|
size_t len = 0;
|
67
71
|
|
68
72
|
if (prefix != NULL)
|
69
73
|
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
70
|
-
|
74
|
+
strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len);
|
71
75
|
__redisSetError(c,type,buf);
|
72
76
|
}
|
73
77
|
|
@@ -132,14 +136,13 @@ int redisKeepAlive(redisContext *c, int interval) {
|
|
132
136
|
|
133
137
|
val = interval;
|
134
138
|
|
135
|
-
#
|
139
|
+
#if defined(__APPLE__) && defined(__MACH__)
|
136
140
|
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
|
137
141
|
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
138
142
|
return REDIS_ERR;
|
139
143
|
}
|
140
144
|
#else
|
141
145
|
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
|
142
|
-
val = interval;
|
143
146
|
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
|
144
147
|
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
145
148
|
return REDIS_ERR;
|
@@ -175,19 +178,15 @@ static int redisSetTcpNoDelay(redisContext *c) {
|
|
175
178
|
|
176
179
|
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
|
177
180
|
|
178
|
-
static int
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
msec = -1;
|
183
|
-
wfd[0].fd = c->fd;
|
184
|
-
wfd[0].events = POLLOUT;
|
181
|
+
static int redisContextTimeoutMsec(redisContext *c, long *result)
|
182
|
+
{
|
183
|
+
const struct timeval *timeout = c->timeout;
|
184
|
+
long msec = -1;
|
185
185
|
|
186
186
|
/* Only use timeout when not NULL. */
|
187
187
|
if (timeout != NULL) {
|
188
188
|
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
|
189
|
-
|
190
|
-
redisContextCloseFd(c);
|
189
|
+
*result = msec;
|
191
190
|
return REDIS_ERR;
|
192
191
|
}
|
193
192
|
|
@@ -198,6 +197,16 @@ static int redisContextWaitReady(redisContext *c, const struct timeval *timeout)
|
|
198
197
|
}
|
199
198
|
}
|
200
199
|
|
200
|
+
*result = msec;
|
201
|
+
return REDIS_OK;
|
202
|
+
}
|
203
|
+
|
204
|
+
static int redisContextWaitReady(redisContext *c, long msec) {
|
205
|
+
struct pollfd wfd[1];
|
206
|
+
|
207
|
+
wfd[0].fd = c->fd;
|
208
|
+
wfd[0].events = POLLOUT;
|
209
|
+
|
201
210
|
if (errno == EINPROGRESS) {
|
202
211
|
int res;
|
203
212
|
|
@@ -262,6 +271,49 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
|
262
271
|
int blocking = (c->flags & REDIS_BLOCK);
|
263
272
|
int reuseaddr = (c->flags & REDIS_REUSEADDR);
|
264
273
|
int reuses = 0;
|
274
|
+
long timeout_msec = -1;
|
275
|
+
|
276
|
+
servinfo = NULL;
|
277
|
+
c->connection_type = REDIS_CONN_TCP;
|
278
|
+
c->tcp.port = port;
|
279
|
+
|
280
|
+
/* We need to take possession of the passed parameters
|
281
|
+
* to make them reusable for a reconnect.
|
282
|
+
* We also carefully check we don't free data we already own,
|
283
|
+
* as in the case of the reconnect method.
|
284
|
+
*
|
285
|
+
* This is a bit ugly, but atleast it works and doesn't leak memory.
|
286
|
+
**/
|
287
|
+
if (c->tcp.host != addr) {
|
288
|
+
free(c->tcp.host);
|
289
|
+
|
290
|
+
c->tcp.host = strdup(addr);
|
291
|
+
}
|
292
|
+
|
293
|
+
if (timeout) {
|
294
|
+
if (c->timeout != timeout) {
|
295
|
+
if (c->timeout == NULL)
|
296
|
+
c->timeout = malloc(sizeof(struct timeval));
|
297
|
+
|
298
|
+
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
299
|
+
}
|
300
|
+
} else {
|
301
|
+
free(c->timeout);
|
302
|
+
c->timeout = NULL;
|
303
|
+
}
|
304
|
+
|
305
|
+
if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
|
306
|
+
__redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified");
|
307
|
+
goto error;
|
308
|
+
}
|
309
|
+
|
310
|
+
if (source_addr == NULL) {
|
311
|
+
free(c->tcp.source_addr);
|
312
|
+
c->tcp.source_addr = NULL;
|
313
|
+
} else if (c->tcp.source_addr != source_addr) {
|
314
|
+
free(c->tcp.source_addr);
|
315
|
+
c->tcp.source_addr = strdup(source_addr);
|
316
|
+
}
|
265
317
|
|
266
318
|
snprintf(_port, 6, "%d", port);
|
267
319
|
memset(&hints,0,sizeof(hints));
|
@@ -273,7 +325,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
|
273
325
|
* as this would add latency to every connect. Otherwise a more sensible
|
274
326
|
* route could be: Use IPv6 if both addresses are available and there is IPv6
|
275
327
|
* connectivity. */
|
276
|
-
if ((rv = getaddrinfo(
|
328
|
+
if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) {
|
277
329
|
hints.ai_family = AF_INET6;
|
278
330
|
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
|
279
331
|
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
|
@@ -288,10 +340,10 @@ addrretry:
|
|
288
340
|
c->fd = s;
|
289
341
|
if (redisSetBlocking(c,0) != REDIS_OK)
|
290
342
|
goto error;
|
291
|
-
if (source_addr) {
|
343
|
+
if (c->tcp.source_addr) {
|
292
344
|
int bound = 0;
|
293
345
|
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
|
294
|
-
if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) {
|
346
|
+
if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) {
|
295
347
|
char buf[128];
|
296
348
|
snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
|
297
349
|
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
@@ -302,6 +354,7 @@ addrretry:
|
|
302
354
|
n = 1;
|
303
355
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
|
304
356
|
sizeof(n)) < 0) {
|
357
|
+
freeaddrinfo(bservinfo);
|
305
358
|
goto error;
|
306
359
|
}
|
307
360
|
}
|
@@ -330,10 +383,11 @@ addrretry:
|
|
330
383
|
if (++reuses >= REDIS_CONNECT_RETRIES) {
|
331
384
|
goto error;
|
332
385
|
} else {
|
386
|
+
redisContextCloseFd(c);
|
333
387
|
goto addrretry;
|
334
388
|
}
|
335
389
|
} else {
|
336
|
-
if (redisContextWaitReady(c,
|
390
|
+
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
|
337
391
|
goto error;
|
338
392
|
}
|
339
393
|
}
|
@@ -356,7 +410,10 @@ addrretry:
|
|
356
410
|
error:
|
357
411
|
rv = REDIS_ERR;
|
358
412
|
end:
|
359
|
-
|
413
|
+
if(servinfo) {
|
414
|
+
freeaddrinfo(servinfo);
|
415
|
+
}
|
416
|
+
|
360
417
|
return rv; // Need to return REDIS_OK if alright
|
361
418
|
}
|
362
419
|
|
@@ -374,19 +431,39 @@ int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
|
374
431
|
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
|
375
432
|
int blocking = (c->flags & REDIS_BLOCK);
|
376
433
|
struct sockaddr_un sa;
|
434
|
+
long timeout_msec = -1;
|
377
435
|
|
378
|
-
if (redisCreateSocket(c,
|
436
|
+
if (redisCreateSocket(c,AF_UNIX) < 0)
|
379
437
|
return REDIS_ERR;
|
380
438
|
if (redisSetBlocking(c,0) != REDIS_OK)
|
381
439
|
return REDIS_ERR;
|
382
440
|
|
383
|
-
|
441
|
+
c->connection_type = REDIS_CONN_UNIX;
|
442
|
+
if (c->unix_sock.path != path)
|
443
|
+
c->unix_sock.path = strdup(path);
|
444
|
+
|
445
|
+
if (timeout) {
|
446
|
+
if (c->timeout != timeout) {
|
447
|
+
if (c->timeout == NULL)
|
448
|
+
c->timeout = malloc(sizeof(struct timeval));
|
449
|
+
|
450
|
+
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
451
|
+
}
|
452
|
+
} else {
|
453
|
+
free(c->timeout);
|
454
|
+
c->timeout = NULL;
|
455
|
+
}
|
456
|
+
|
457
|
+
if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
|
458
|
+
return REDIS_ERR;
|
459
|
+
|
460
|
+
sa.sun_family = AF_UNIX;
|
384
461
|
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
385
462
|
if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
386
463
|
if (errno == EINPROGRESS && !blocking) {
|
387
464
|
/* This is ok. */
|
388
465
|
} else {
|
389
|
-
if (redisContextWaitReady(c,
|
466
|
+
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
|
390
467
|
return REDIS_ERR;
|
391
468
|
}
|
392
469
|
}
|