hiredis 0.5.2 → 0.6.0
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 +4 -4
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/Makefile +78 -32
- data/vendor/hiredis/async.c +84 -21
- data/vendor/hiredis/async.h +4 -0
- data/vendor/hiredis/fmacros.h +7 -2
- data/vendor/hiredis/hiredis.c +228 -534
- data/vendor/hiredis/hiredis.h +53 -74
- data/vendor/hiredis/net.c +155 -46
- data/vendor/hiredis/net.h +8 -4
- data/vendor/hiredis/read.c +523 -0
- data/vendor/hiredis/read.h +116 -0
- data/vendor/hiredis/sds.c +610 -120
- data/vendor/hiredis/sds.h +27 -13
- data/vendor/hiredis/test.c +106 -12
- metadata +44 -28
- data/lib/hiredis/errors.rb +0 -5
data/vendor/hiredis/hiredis.h
CHANGED
@@ -31,27 +31,16 @@
|
|
31
31
|
|
32
32
|
#ifndef __HIREDIS_H
|
33
33
|
#define __HIREDIS_H
|
34
|
-
#include
|
34
|
+
#include "read.h"
|
35
35
|
#include <stdarg.h> /* for va_list */
|
36
36
|
#include <sys/time.h> /* for struct timeval */
|
37
|
+
#include <stdint.h> /* uintXX_t, etc */
|
38
|
+
#include "sds.h" /* for sds */
|
37
39
|
|
38
40
|
#define HIREDIS_MAJOR 0
|
39
|
-
#define HIREDIS_MINOR
|
41
|
+
#define HIREDIS_MINOR 12
|
40
42
|
#define HIREDIS_PATCH 0
|
41
43
|
|
42
|
-
#define REDIS_ERR -1
|
43
|
-
#define REDIS_OK 0
|
44
|
-
|
45
|
-
/* When an error occurs, the err flag in a context is set to hold the type of
|
46
|
-
* error that occured. REDIS_ERR_IO means there was an I/O error and you
|
47
|
-
* should use the "errno" variable to find out what is wrong.
|
48
|
-
* For other values, the "errstr" field will hold a description. */
|
49
|
-
#define REDIS_ERR_IO 1 /* Error in read or write */
|
50
|
-
#define REDIS_ERR_EOF 3 /* End of file */
|
51
|
-
#define REDIS_ERR_PROTOCOL 4 /* Protocol error */
|
52
|
-
#define REDIS_ERR_OOM 5 /* Out of memory */
|
53
|
-
#define REDIS_ERR_OTHER 2 /* Everything else... */
|
54
|
-
|
55
44
|
/* Connection type can be blocking or non-blocking and is set in the
|
56
45
|
* least significant bit of the flags field in redisContext. */
|
57
46
|
#define REDIS_BLOCK 0x1
|
@@ -79,14 +68,38 @@
|
|
79
68
|
/* Flag that is set when monitor mode is active */
|
80
69
|
#define REDIS_MONITORING 0x40
|
81
70
|
|
82
|
-
|
83
|
-
#define
|
84
|
-
|
85
|
-
#define
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
#define
|
71
|
+
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
|
72
|
+
#define REDIS_REUSEADDR 0x80
|
73
|
+
|
74
|
+
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
|
75
|
+
|
76
|
+
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
|
77
|
+
* SO_REUSEADDR is being used. */
|
78
|
+
#define REDIS_CONNECT_RETRIES 10
|
79
|
+
|
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
|
90
103
|
|
91
104
|
#ifdef __cplusplus
|
92
105
|
extern "C" {
|
@@ -102,55 +115,7 @@ typedef struct redisReply {
|
|
102
115
|
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
|
103
116
|
} redisReply;
|
104
117
|
|
105
|
-
typedef struct redisReadTask {
|
106
|
-
int type;
|
107
|
-
int elements; /* number of elements in multibulk container */
|
108
|
-
int idx; /* index in parent (array) object */
|
109
|
-
void *obj; /* holds user-generated value for a read task */
|
110
|
-
struct redisReadTask *parent; /* parent task */
|
111
|
-
void *privdata; /* user-settable arbitrary field */
|
112
|
-
} redisReadTask;
|
113
|
-
|
114
|
-
typedef struct redisReplyObjectFunctions {
|
115
|
-
void *(*createString)(const redisReadTask*, char*, size_t);
|
116
|
-
void *(*createArray)(const redisReadTask*, int);
|
117
|
-
void *(*createInteger)(const redisReadTask*, long long);
|
118
|
-
void *(*createNil)(const redisReadTask*);
|
119
|
-
void (*freeObject)(void*);
|
120
|
-
} redisReplyObjectFunctions;
|
121
|
-
|
122
|
-
/* State for the protocol parser */
|
123
|
-
typedef struct redisReader {
|
124
|
-
int err; /* Error flags, 0 when there is no error */
|
125
|
-
char errstr[128]; /* String representation of error when applicable */
|
126
|
-
|
127
|
-
char *buf; /* Read buffer */
|
128
|
-
size_t pos; /* Buffer cursor */
|
129
|
-
size_t len; /* Buffer length */
|
130
|
-
size_t maxbuf; /* Max length of unused buffer */
|
131
|
-
|
132
|
-
redisReadTask rstack[9];
|
133
|
-
int ridx; /* Index of current read task */
|
134
|
-
void *reply; /* Temporary reply pointer */
|
135
|
-
|
136
|
-
redisReplyObjectFunctions *fn;
|
137
|
-
void *privdata;
|
138
|
-
} redisReader;
|
139
|
-
|
140
|
-
/* Public API for the protocol parser. */
|
141
118
|
redisReader *redisReaderCreate(void);
|
142
|
-
void redisReaderFree(redisReader *r);
|
143
|
-
int redisReaderFeed(redisReader *r, const char *buf, size_t len);
|
144
|
-
int redisReaderGetReply(redisReader *r, void **reply);
|
145
|
-
|
146
|
-
/* Backwards compatibility, can be removed on big version bump. */
|
147
|
-
#define redisReplyReaderCreate redisReaderCreate
|
148
|
-
#define redisReplyReaderFree redisReaderFree
|
149
|
-
#define redisReplyReaderFeed redisReaderFeed
|
150
|
-
#define redisReplyReaderGetReply redisReaderGetReply
|
151
|
-
#define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p))
|
152
|
-
#define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply)
|
153
|
-
#define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr)
|
154
119
|
|
155
120
|
/* Function to free the reply objects hiredis returns by default. */
|
156
121
|
void freeReplyObject(void *reply);
|
@@ -159,6 +124,9 @@ void freeReplyObject(void *reply);
|
|
159
124
|
int redisvFormatCommand(char **target, const char *format, va_list ap);
|
160
125
|
int redisFormatCommand(char **target, const char *format, ...);
|
161
126
|
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
|
127
|
+
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
|
128
|
+
void redisFreeCommand(char *cmd);
|
129
|
+
void redisFreeSdsCommand(sds cmd);
|
162
130
|
|
163
131
|
/* Context for a connection to Redis */
|
164
132
|
typedef struct redisContext {
|
@@ -171,13 +139,20 @@ typedef struct redisContext {
|
|
171
139
|
} redisContext;
|
172
140
|
|
173
141
|
redisContext *redisConnect(const char *ip, int port);
|
174
|
-
redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv);
|
142
|
+
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
|
175
143
|
redisContext *redisConnectNonBlock(const char *ip, int port);
|
144
|
+
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
145
|
+
const char *source_addr);
|
146
|
+
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
147
|
+
const char *source_addr);
|
176
148
|
redisContext *redisConnectUnix(const char *path);
|
177
|
-
redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv);
|
149
|
+
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
178
150
|
redisContext *redisConnectUnixNonBlock(const char *path);
|
179
|
-
|
151
|
+
redisContext *redisConnectFd(int fd);
|
152
|
+
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
153
|
+
int redisEnableKeepAlive(redisContext *c);
|
180
154
|
void redisFree(redisContext *c);
|
155
|
+
int redisFreeKeepFd(redisContext *c);
|
181
156
|
int redisBufferRead(redisContext *c);
|
182
157
|
int redisBufferWrite(redisContext *c, int *done);
|
183
158
|
|
@@ -188,6 +163,10 @@ int redisBufferWrite(redisContext *c, int *done);
|
|
188
163
|
int redisGetReply(redisContext *c, void **reply);
|
189
164
|
int redisGetReplyFromReader(redisContext *c, void **reply);
|
190
165
|
|
166
|
+
/* Write a formatted command to the output buffer. Use these functions in blocking mode
|
167
|
+
* to get a pipeline of commands. */
|
168
|
+
int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);
|
169
|
+
|
191
170
|
/* Write a command to the output buffer. Use these functions in blocking mode
|
192
171
|
* to get a pipeline of commands. */
|
193
172
|
int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
|
data/vendor/hiredis/net.c
CHANGED
@@ -54,21 +54,28 @@
|
|
54
54
|
/* Defined in hiredis.c */
|
55
55
|
void __redisSetError(redisContext *c, int type, const char *str);
|
56
56
|
|
57
|
+
static void redisContextCloseFd(redisContext *c) {
|
58
|
+
if (c && c->fd >= 0) {
|
59
|
+
close(c->fd);
|
60
|
+
c->fd = -1;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
57
64
|
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
|
58
|
-
char buf[128];
|
65
|
+
char buf[128] = { 0 };
|
59
66
|
size_t len = 0;
|
60
67
|
|
61
68
|
if (prefix != NULL)
|
62
69
|
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
63
|
-
|
70
|
+
__redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len);
|
64
71
|
__redisSetError(c,type,buf);
|
65
72
|
}
|
66
73
|
|
67
|
-
static int redisSetReuseAddr(redisContext *c
|
74
|
+
static int redisSetReuseAddr(redisContext *c) {
|
68
75
|
int on = 1;
|
69
|
-
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
76
|
+
if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
70
77
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
71
|
-
|
78
|
+
redisContextCloseFd(c);
|
72
79
|
return REDIS_ERR;
|
73
80
|
}
|
74
81
|
return REDIS_OK;
|
@@ -80,23 +87,24 @@ static int redisCreateSocket(redisContext *c, int type) {
|
|
80
87
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
81
88
|
return REDIS_ERR;
|
82
89
|
}
|
90
|
+
c->fd = s;
|
83
91
|
if (type == AF_INET) {
|
84
|
-
if (redisSetReuseAddr(c
|
92
|
+
if (redisSetReuseAddr(c) == REDIS_ERR) {
|
85
93
|
return REDIS_ERR;
|
86
94
|
}
|
87
95
|
}
|
88
|
-
return
|
96
|
+
return REDIS_OK;
|
89
97
|
}
|
90
98
|
|
91
|
-
static int redisSetBlocking(redisContext *c, int
|
99
|
+
static int redisSetBlocking(redisContext *c, int blocking) {
|
92
100
|
int flags;
|
93
101
|
|
94
102
|
/* Set the socket nonblocking.
|
95
103
|
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
|
96
104
|
* interrupted by a signal. */
|
97
|
-
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
105
|
+
if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
|
98
106
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
|
99
|
-
|
107
|
+
redisContextCloseFd(c);
|
100
108
|
return REDIS_ERR;
|
101
109
|
}
|
102
110
|
|
@@ -105,19 +113,61 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) {
|
|
105
113
|
else
|
106
114
|
flags |= O_NONBLOCK;
|
107
115
|
|
108
|
-
if (fcntl(fd, F_SETFL, flags) == -1) {
|
116
|
+
if (fcntl(c->fd, F_SETFL, flags) == -1) {
|
109
117
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
|
110
|
-
|
118
|
+
redisContextCloseFd(c);
|
119
|
+
return REDIS_ERR;
|
120
|
+
}
|
121
|
+
return REDIS_OK;
|
122
|
+
}
|
123
|
+
|
124
|
+
int redisKeepAlive(redisContext *c, int interval) {
|
125
|
+
int val = 1;
|
126
|
+
int fd = c->fd;
|
127
|
+
|
128
|
+
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
|
129
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
130
|
+
return REDIS_ERR;
|
131
|
+
}
|
132
|
+
|
133
|
+
val = interval;
|
134
|
+
|
135
|
+
#ifdef _OSX
|
136
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
|
137
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
138
|
+
return REDIS_ERR;
|
139
|
+
}
|
140
|
+
#else
|
141
|
+
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
|
142
|
+
val = interval;
|
143
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
|
144
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
145
|
+
return REDIS_ERR;
|
146
|
+
}
|
147
|
+
|
148
|
+
val = interval/3;
|
149
|
+
if (val == 0) val = 1;
|
150
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
|
151
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
152
|
+
return REDIS_ERR;
|
153
|
+
}
|
154
|
+
|
155
|
+
val = 3;
|
156
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
|
157
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
111
158
|
return REDIS_ERR;
|
112
159
|
}
|
160
|
+
#endif
|
161
|
+
#endif
|
162
|
+
|
113
163
|
return REDIS_OK;
|
114
164
|
}
|
115
165
|
|
116
|
-
static int redisSetTcpNoDelay(redisContext *c
|
166
|
+
static int redisSetTcpNoDelay(redisContext *c) {
|
117
167
|
int yes = 1;
|
118
|
-
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
168
|
+
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
119
169
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
|
120
|
-
|
170
|
+
redisContextCloseFd(c);
|
121
171
|
return REDIS_ERR;
|
122
172
|
}
|
123
173
|
return REDIS_OK;
|
@@ -125,18 +175,19 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
|
|
125
175
|
|
126
176
|
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
|
127
177
|
|
128
|
-
static int redisContextWaitReady(redisContext *c,
|
178
|
+
static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) {
|
129
179
|
struct pollfd wfd[1];
|
130
180
|
long msec;
|
131
181
|
|
132
182
|
msec = -1;
|
133
|
-
wfd[0].fd = fd;
|
183
|
+
wfd[0].fd = c->fd;
|
134
184
|
wfd[0].events = POLLOUT;
|
135
185
|
|
136
186
|
/* Only use timeout when not NULL. */
|
137
187
|
if (timeout != NULL) {
|
138
188
|
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
|
139
|
-
|
189
|
+
__redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
|
190
|
+
redisContextCloseFd(c);
|
140
191
|
return REDIS_ERR;
|
141
192
|
}
|
142
193
|
|
@@ -152,47 +203,45 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
|
|
152
203
|
|
153
204
|
if ((res = poll(wfd, 1, msec)) == -1) {
|
154
205
|
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
|
155
|
-
|
206
|
+
redisContextCloseFd(c);
|
156
207
|
return REDIS_ERR;
|
157
208
|
} else if (res == 0) {
|
158
209
|
errno = ETIMEDOUT;
|
159
210
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
160
|
-
|
211
|
+
redisContextCloseFd(c);
|
161
212
|
return REDIS_ERR;
|
162
213
|
}
|
163
214
|
|
164
|
-
if (redisCheckSocketError(c
|
215
|
+
if (redisCheckSocketError(c) != REDIS_OK)
|
165
216
|
return REDIS_ERR;
|
166
217
|
|
167
218
|
return REDIS_OK;
|
168
219
|
}
|
169
220
|
|
170
221
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
171
|
-
|
222
|
+
redisContextCloseFd(c);
|
172
223
|
return REDIS_ERR;
|
173
224
|
}
|
174
225
|
|
175
|
-
int redisCheckSocketError(redisContext *c
|
226
|
+
int redisCheckSocketError(redisContext *c) {
|
176
227
|
int err = 0;
|
177
228
|
socklen_t errlen = sizeof(err);
|
178
229
|
|
179
|
-
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
230
|
+
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
180
231
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)");
|
181
|
-
close(fd);
|
182
232
|
return REDIS_ERR;
|
183
233
|
}
|
184
234
|
|
185
235
|
if (err) {
|
186
236
|
errno = err;
|
187
237
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
188
|
-
close(fd);
|
189
238
|
return REDIS_ERR;
|
190
239
|
}
|
191
240
|
|
192
241
|
return REDIS_OK;
|
193
242
|
}
|
194
243
|
|
195
|
-
int redisContextSetTimeout(redisContext *c, struct timeval tv) {
|
244
|
+
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
196
245
|
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
|
197
246
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
|
198
247
|
return REDIS_ERR;
|
@@ -204,44 +253,95 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv) {
|
|
204
253
|
return REDIS_OK;
|
205
254
|
}
|
206
255
|
|
207
|
-
int
|
208
|
-
|
256
|
+
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
257
|
+
const struct timeval *timeout,
|
258
|
+
const char *source_addr) {
|
259
|
+
int s, rv, n;
|
209
260
|
char _port[6]; /* strlen("65535"); */
|
210
|
-
struct addrinfo hints, *servinfo, *p;
|
261
|
+
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
|
211
262
|
int blocking = (c->flags & REDIS_BLOCK);
|
263
|
+
int reuseaddr = (c->flags & REDIS_REUSEADDR);
|
264
|
+
int reuses = 0;
|
212
265
|
|
213
266
|
snprintf(_port, 6, "%d", port);
|
214
267
|
memset(&hints,0,sizeof(hints));
|
215
268
|
hints.ai_family = AF_INET;
|
216
269
|
hints.ai_socktype = SOCK_STREAM;
|
217
270
|
|
271
|
+
/* Try with IPv6 if no IPv4 address was found. We do it in this order since
|
272
|
+
* in a Redis client you can't afford to test if you have IPv6 connectivity
|
273
|
+
* as this would add latency to every connect. Otherwise a more sensible
|
274
|
+
* route could be: Use IPv6 if both addresses are available and there is IPv6
|
275
|
+
* connectivity. */
|
218
276
|
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
|
219
|
-
|
220
|
-
|
277
|
+
hints.ai_family = AF_INET6;
|
278
|
+
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
|
279
|
+
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
|
280
|
+
return REDIS_ERR;
|
281
|
+
}
|
221
282
|
}
|
222
283
|
for (p = servinfo; p != NULL; p = p->ai_next) {
|
284
|
+
addrretry:
|
223
285
|
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
|
224
286
|
continue;
|
225
287
|
|
226
|
-
|
288
|
+
c->fd = s;
|
289
|
+
if (redisSetBlocking(c,0) != REDIS_OK)
|
227
290
|
goto error;
|
291
|
+
if (source_addr) {
|
292
|
+
int bound = 0;
|
293
|
+
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
|
294
|
+
if ((rv = getaddrinfo(source_addr, NULL, &hints, &bservinfo)) != 0) {
|
295
|
+
char buf[128];
|
296
|
+
snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
|
297
|
+
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
298
|
+
goto error;
|
299
|
+
}
|
300
|
+
|
301
|
+
if (reuseaddr) {
|
302
|
+
n = 1;
|
303
|
+
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
|
304
|
+
sizeof(n)) < 0) {
|
305
|
+
goto error;
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
for (b = bservinfo; b != NULL; b = b->ai_next) {
|
310
|
+
if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
|
311
|
+
bound = 1;
|
312
|
+
break;
|
313
|
+
}
|
314
|
+
}
|
315
|
+
freeaddrinfo(bservinfo);
|
316
|
+
if (!bound) {
|
317
|
+
char buf[128];
|
318
|
+
snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno));
|
319
|
+
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
320
|
+
goto error;
|
321
|
+
}
|
322
|
+
}
|
228
323
|
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
|
229
324
|
if (errno == EHOSTUNREACH) {
|
230
|
-
|
325
|
+
redisContextCloseFd(c);
|
231
326
|
continue;
|
232
327
|
} else if (errno == EINPROGRESS && !blocking) {
|
233
328
|
/* This is ok. */
|
329
|
+
} else if (errno == EADDRNOTAVAIL && reuseaddr) {
|
330
|
+
if (++reuses >= REDIS_CONNECT_RETRIES) {
|
331
|
+
goto error;
|
332
|
+
} else {
|
333
|
+
goto addrretry;
|
334
|
+
}
|
234
335
|
} else {
|
235
|
-
if (redisContextWaitReady(c,
|
336
|
+
if (redisContextWaitReady(c,timeout) != REDIS_OK)
|
236
337
|
goto error;
|
237
338
|
}
|
238
339
|
}
|
239
|
-
if (blocking && redisSetBlocking(c,
|
340
|
+
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
240
341
|
goto error;
|
241
|
-
if (redisSetTcpNoDelay(c
|
342
|
+
if (redisSetTcpNoDelay(c) != REDIS_OK)
|
242
343
|
goto error;
|
243
344
|
|
244
|
-
c->fd = s;
|
245
345
|
c->flags |= REDIS_CONNECTED;
|
246
346
|
rv = REDIS_OK;
|
247
347
|
goto end;
|
@@ -260,32 +360,41 @@ end:
|
|
260
360
|
return rv; // Need to return REDIS_OK if alright
|
261
361
|
}
|
262
362
|
|
263
|
-
int
|
264
|
-
|
363
|
+
int redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
364
|
+
const struct timeval *timeout) {
|
365
|
+
return _redisContextConnectTcp(c, addr, port, timeout, NULL);
|
366
|
+
}
|
367
|
+
|
368
|
+
int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
369
|
+
const struct timeval *timeout,
|
370
|
+
const char *source_addr) {
|
371
|
+
return _redisContextConnectTcp(c, addr, port, timeout, source_addr);
|
372
|
+
}
|
373
|
+
|
374
|
+
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
|
265
375
|
int blocking = (c->flags & REDIS_BLOCK);
|
266
376
|
struct sockaddr_un sa;
|
267
377
|
|
268
|
-
if (
|
378
|
+
if (redisCreateSocket(c,AF_LOCAL) < 0)
|
269
379
|
return REDIS_ERR;
|
270
|
-
if (redisSetBlocking(c,
|
380
|
+
if (redisSetBlocking(c,0) != REDIS_OK)
|
271
381
|
return REDIS_ERR;
|
272
382
|
|
273
383
|
sa.sun_family = AF_LOCAL;
|
274
384
|
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
275
|
-
if (connect(
|
385
|
+
if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
276
386
|
if (errno == EINPROGRESS && !blocking) {
|
277
387
|
/* This is ok. */
|
278
388
|
} else {
|
279
|
-
if (redisContextWaitReady(c,
|
389
|
+
if (redisContextWaitReady(c,timeout) != REDIS_OK)
|
280
390
|
return REDIS_ERR;
|
281
391
|
}
|
282
392
|
}
|
283
393
|
|
284
394
|
/* Reset socket to be blocking after connect(2). */
|
285
|
-
if (blocking && redisSetBlocking(c,
|
395
|
+
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
286
396
|
return REDIS_ERR;
|
287
397
|
|
288
|
-
c->fd = s;
|
289
398
|
c->flags |= REDIS_CONNECTED;
|
290
399
|
return REDIS_OK;
|
291
400
|
}
|