durable_rules 0.33.13 → 0.34.01
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/deps/hiredis/Makefile +110 -41
- data/deps/hiredis/async.c +87 -22
- data/deps/hiredis/async.h +4 -0
- data/deps/hiredis/fmacros.h +6 -1
- data/deps/hiredis/hiredis.c +270 -534
- data/deps/hiredis/hiredis.h +89 -76
- data/deps/hiredis/net.c +206 -47
- data/deps/hiredis/net.h +12 -6
- data/deps/hiredis/read.c +525 -0
- data/deps/hiredis/read.h +116 -0
- data/deps/hiredis/sds.c +260 -47
- data/deps/hiredis/sds.h +11 -6
- data/deps/hiredis/test.c +171 -18
- data/deps/hiredis/win32.h +42 -0
- data/librb/durable.rb +35 -6
- data/librb/engine.rb +173 -40
- data/src/rules/events.c +42 -4
- data/src/rules/net.c +184 -96
- data/src/rules/net.h +10 -0
- data/src/rules/rules.h +13 -0
- data/src/rulesrb/rules.c +55 -0
- metadata +5 -3
- data/deps/hiredis/zmalloc.h +0 -13
data/deps/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
|
*
|
|
@@ -31,26 +33,16 @@
|
|
|
31
33
|
|
|
32
34
|
#ifndef __HIREDIS_H
|
|
33
35
|
#define __HIREDIS_H
|
|
34
|
-
#include
|
|
36
|
+
#include "read.h"
|
|
35
37
|
#include <stdarg.h> /* for va_list */
|
|
36
38
|
#include <sys/time.h> /* for struct timeval */
|
|
39
|
+
#include <stdint.h> /* uintXX_t, etc */
|
|
40
|
+
#include "sds.h" /* for sds */
|
|
37
41
|
|
|
38
42
|
#define HIREDIS_MAJOR 0
|
|
39
|
-
#define HIREDIS_MINOR
|
|
40
|
-
#define HIREDIS_PATCH
|
|
41
|
-
|
|
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... */
|
|
43
|
+
#define HIREDIS_MINOR 13
|
|
44
|
+
#define HIREDIS_PATCH 3
|
|
45
|
+
#define HIREDIS_SONAME 0.13
|
|
54
46
|
|
|
55
47
|
/* Connection type can be blocking or non-blocking and is set in the
|
|
56
48
|
* least significant bit of the flags field in redisContext. */
|
|
@@ -79,14 +71,38 @@
|
|
|
79
71
|
/* Flag that is set when monitor mode is active */
|
|
80
72
|
#define REDIS_MONITORING 0x40
|
|
81
73
|
|
|
82
|
-
|
|
83
|
-
#define
|
|
84
|
-
|
|
85
|
-
#define
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
#define
|
|
74
|
+
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
|
|
75
|
+
#define REDIS_REUSEADDR 0x80
|
|
76
|
+
|
|
77
|
+
#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */
|
|
78
|
+
|
|
79
|
+
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
|
|
80
|
+
* SO_REUSEADDR is being used. */
|
|
81
|
+
#define REDIS_CONNECT_RETRIES 10
|
|
82
|
+
|
|
83
|
+
/* strerror_r has two completely different prototypes and behaviors
|
|
84
|
+
* depending on system issues, so we need to operate on the error buffer
|
|
85
|
+
* differently depending on which strerror_r we're using. */
|
|
86
|
+
#ifndef _GNU_SOURCE_PLUS
|
|
87
|
+
/* "regular" POSIX strerror_r that does the right thing. */
|
|
88
|
+
#define __redis_strerror_r(errno, buf, len) \
|
|
89
|
+
do { \
|
|
90
|
+
strerror_r((errno), (buf), (len)); \
|
|
91
|
+
} while (0)
|
|
92
|
+
#else
|
|
93
|
+
/* "bad" GNU strerror_r we need to clean up after. */
|
|
94
|
+
#define __redis_strerror_r(errno, buf, len) \
|
|
95
|
+
do { \
|
|
96
|
+
char *err_str = strerror_r((errno), (buf), (len)); \
|
|
97
|
+
/* If return value _isn't_ the start of the buffer we passed in, \
|
|
98
|
+
* then GNU strerror_r returned an internal static buffer and we \
|
|
99
|
+
* need to copy the result into our private buffer. */ \
|
|
100
|
+
if (err_str != (buf)) { \
|
|
101
|
+
buf[(len)] = '\0'; \
|
|
102
|
+
strncat((buf), err_str, ((len) - 1)); \
|
|
103
|
+
} \
|
|
104
|
+
} while (0)
|
|
105
|
+
#endif
|
|
90
106
|
|
|
91
107
|
#ifdef __cplusplus
|
|
92
108
|
extern "C" {
|
|
@@ -102,55 +118,7 @@ typedef struct redisReply {
|
|
|
102
118
|
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
|
|
103
119
|
} redisReply;
|
|
104
120
|
|
|
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
121
|
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
122
|
|
|
155
123
|
/* Function to free the reply objects hiredis returns by default. */
|
|
156
124
|
void freeReplyObject(void *reply);
|
|
@@ -159,6 +127,14 @@ void freeReplyObject(void *reply);
|
|
|
159
127
|
int redisvFormatCommand(char **target, const char *format, va_list ap);
|
|
160
128
|
int redisFormatCommand(char **target, const char *format, ...);
|
|
161
129
|
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
|
|
130
|
+
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
|
|
131
|
+
void redisFreeCommand(char *cmd);
|
|
132
|
+
void redisFreeSdsCommand(sds cmd);
|
|
133
|
+
|
|
134
|
+
enum redisConnectionType {
|
|
135
|
+
REDIS_CONN_TCP,
|
|
136
|
+
REDIS_CONN_UNIX,
|
|
137
|
+
};
|
|
162
138
|
|
|
163
139
|
/* Context for a connection to Redis */
|
|
164
140
|
typedef struct redisContext {
|
|
@@ -168,16 +144,49 @@ typedef struct redisContext {
|
|
|
168
144
|
int flags;
|
|
169
145
|
char *obuf; /* Write buffer */
|
|
170
146
|
redisReader *reader; /* Protocol reader */
|
|
147
|
+
|
|
148
|
+
enum redisConnectionType connection_type;
|
|
149
|
+
struct timeval *timeout;
|
|
150
|
+
|
|
151
|
+
struct {
|
|
152
|
+
char *host;
|
|
153
|
+
char *source_addr;
|
|
154
|
+
int port;
|
|
155
|
+
} tcp;
|
|
156
|
+
|
|
157
|
+
struct {
|
|
158
|
+
char *path;
|
|
159
|
+
} unix_sock;
|
|
160
|
+
|
|
171
161
|
} redisContext;
|
|
172
162
|
|
|
173
163
|
redisContext *redisConnect(const char *ip, int port);
|
|
174
|
-
redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv);
|
|
164
|
+
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
|
|
175
165
|
redisContext *redisConnectNonBlock(const char *ip, int port);
|
|
166
|
+
redisContext *redisConnectBindNonBlock(const char *ip, int port,
|
|
167
|
+
const char *source_addr);
|
|
168
|
+
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
|
|
169
|
+
const char *source_addr);
|
|
176
170
|
redisContext *redisConnectUnix(const char *path);
|
|
177
|
-
redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv);
|
|
171
|
+
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
|
|
178
172
|
redisContext *redisConnectUnixNonBlock(const char *path);
|
|
179
|
-
|
|
173
|
+
redisContext *redisConnectFd(int fd);
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Reconnect the given context using the saved information.
|
|
177
|
+
*
|
|
178
|
+
* This re-uses the exact same connect options as in the initial connection.
|
|
179
|
+
* host, ip (or path), timeout and bind address are reused,
|
|
180
|
+
* flags are used unmodified from the existing context.
|
|
181
|
+
*
|
|
182
|
+
* Returns REDIS_OK on successfull connect or REDIS_ERR otherwise.
|
|
183
|
+
*/
|
|
184
|
+
int redisReconnect(redisContext *c);
|
|
185
|
+
|
|
186
|
+
int redisSetTimeout(redisContext *c, const struct timeval tv);
|
|
187
|
+
int redisEnableKeepAlive(redisContext *c);
|
|
180
188
|
void redisFree(redisContext *c);
|
|
189
|
+
int redisFreeKeepFd(redisContext *c);
|
|
181
190
|
int redisBufferRead(redisContext *c);
|
|
182
191
|
int redisBufferWrite(redisContext *c, int *done);
|
|
183
192
|
|
|
@@ -188,6 +197,10 @@ int redisBufferWrite(redisContext *c, int *done);
|
|
|
188
197
|
int redisGetReply(redisContext *c, void **reply);
|
|
189
198
|
int redisGetReplyFromReader(redisContext *c, void **reply);
|
|
190
199
|
|
|
200
|
+
/* Write a formatted command to the output buffer. Use these functions in blocking mode
|
|
201
|
+
* to get a pipeline of commands. */
|
|
202
|
+
int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);
|
|
203
|
+
|
|
191
204
|
/* Write a command to the output buffer. Use these functions in blocking mode
|
|
192
205
|
* to get a pipeline of commands. */
|
|
193
206
|
int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
|
data/deps/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"
|
|
@@ -54,21 +57,28 @@
|
|
|
54
57
|
/* Defined in hiredis.c */
|
|
55
58
|
void __redisSetError(redisContext *c, int type, const char *str);
|
|
56
59
|
|
|
60
|
+
static void redisContextCloseFd(redisContext *c) {
|
|
61
|
+
if (c && c->fd >= 0) {
|
|
62
|
+
close(c->fd);
|
|
63
|
+
c->fd = -1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
57
67
|
static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
|
|
58
|
-
char buf[128];
|
|
68
|
+
char buf[128] = { 0 };
|
|
59
69
|
size_t len = 0;
|
|
60
70
|
|
|
61
71
|
if (prefix != NULL)
|
|
62
72
|
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
|
|
63
|
-
|
|
73
|
+
//__redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len);
|
|
64
74
|
__redisSetError(c,type,buf);
|
|
65
75
|
}
|
|
66
76
|
|
|
67
|
-
static int redisSetReuseAddr(redisContext *c
|
|
77
|
+
static int redisSetReuseAddr(redisContext *c) {
|
|
68
78
|
int on = 1;
|
|
69
|
-
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
|
79
|
+
if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
|
|
70
80
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
|
71
|
-
|
|
81
|
+
redisContextCloseFd(c);
|
|
72
82
|
return REDIS_ERR;
|
|
73
83
|
}
|
|
74
84
|
return REDIS_OK;
|
|
@@ -80,23 +90,24 @@ static int redisCreateSocket(redisContext *c, int type) {
|
|
|
80
90
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
|
81
91
|
return REDIS_ERR;
|
|
82
92
|
}
|
|
93
|
+
c->fd = s;
|
|
83
94
|
if (type == AF_INET) {
|
|
84
|
-
if (redisSetReuseAddr(c
|
|
95
|
+
if (redisSetReuseAddr(c) == REDIS_ERR) {
|
|
85
96
|
return REDIS_ERR;
|
|
86
97
|
}
|
|
87
98
|
}
|
|
88
|
-
return
|
|
99
|
+
return REDIS_OK;
|
|
89
100
|
}
|
|
90
101
|
|
|
91
|
-
static int redisSetBlocking(redisContext *c, int
|
|
102
|
+
static int redisSetBlocking(redisContext *c, int blocking) {
|
|
92
103
|
int flags;
|
|
93
104
|
|
|
94
105
|
/* Set the socket nonblocking.
|
|
95
106
|
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
|
|
96
107
|
* interrupted by a signal. */
|
|
97
|
-
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
|
108
|
+
if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
|
|
98
109
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
|
|
99
|
-
|
|
110
|
+
redisContextCloseFd(c);
|
|
100
111
|
return REDIS_ERR;
|
|
101
112
|
}
|
|
102
113
|
|
|
@@ -105,19 +116,61 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) {
|
|
|
105
116
|
else
|
|
106
117
|
flags |= O_NONBLOCK;
|
|
107
118
|
|
|
108
|
-
if (fcntl(fd, F_SETFL, flags) == -1) {
|
|
119
|
+
if (fcntl(c->fd, F_SETFL, flags) == -1) {
|
|
109
120
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
|
|
110
|
-
|
|
121
|
+
redisContextCloseFd(c);
|
|
111
122
|
return REDIS_ERR;
|
|
112
123
|
}
|
|
113
124
|
return REDIS_OK;
|
|
114
125
|
}
|
|
115
126
|
|
|
116
|
-
|
|
127
|
+
int redisKeepAlive(redisContext *c, int interval) {
|
|
128
|
+
int val = 1;
|
|
129
|
+
int fd = c->fd;
|
|
130
|
+
|
|
131
|
+
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
|
|
132
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
|
133
|
+
return REDIS_ERR;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
val = interval;
|
|
137
|
+
|
|
138
|
+
#ifdef _OSX
|
|
139
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
|
|
140
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
|
141
|
+
return REDIS_ERR;
|
|
142
|
+
}
|
|
143
|
+
#else
|
|
144
|
+
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
|
|
145
|
+
val = interval;
|
|
146
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
|
|
147
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
|
148
|
+
return REDIS_ERR;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
val = interval/3;
|
|
152
|
+
if (val == 0) val = 1;
|
|
153
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
|
|
154
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
|
155
|
+
return REDIS_ERR;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
val = 3;
|
|
159
|
+
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
|
|
160
|
+
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
|
|
161
|
+
return REDIS_ERR;
|
|
162
|
+
}
|
|
163
|
+
#endif
|
|
164
|
+
#endif
|
|
165
|
+
|
|
166
|
+
return REDIS_OK;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
static int redisSetTcpNoDelay(redisContext *c) {
|
|
117
170
|
int yes = 1;
|
|
118
|
-
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
|
171
|
+
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
|
|
119
172
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
|
|
120
|
-
|
|
173
|
+
redisContextCloseFd(c);
|
|
121
174
|
return REDIS_ERR;
|
|
122
175
|
}
|
|
123
176
|
return REDIS_OK;
|
|
@@ -125,18 +178,19 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
|
|
|
125
178
|
|
|
126
179
|
#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
|
|
127
180
|
|
|
128
|
-
static int redisContextWaitReady(redisContext *c,
|
|
181
|
+
static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) {
|
|
129
182
|
struct pollfd wfd[1];
|
|
130
183
|
long msec;
|
|
131
184
|
|
|
132
185
|
msec = -1;
|
|
133
|
-
wfd[0].fd = fd;
|
|
186
|
+
wfd[0].fd = c->fd;
|
|
134
187
|
wfd[0].events = POLLOUT;
|
|
135
188
|
|
|
136
189
|
/* Only use timeout when not NULL. */
|
|
137
190
|
if (timeout != NULL) {
|
|
138
191
|
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
|
|
139
|
-
|
|
192
|
+
__redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
|
|
193
|
+
redisContextCloseFd(c);
|
|
140
194
|
return REDIS_ERR;
|
|
141
195
|
}
|
|
142
196
|
|
|
@@ -152,47 +206,45 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
|
|
|
152
206
|
|
|
153
207
|
if ((res = poll(wfd, 1, msec)) == -1) {
|
|
154
208
|
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
|
|
155
|
-
|
|
209
|
+
redisContextCloseFd(c);
|
|
156
210
|
return REDIS_ERR;
|
|
157
211
|
} else if (res == 0) {
|
|
158
212
|
errno = ETIMEDOUT;
|
|
159
213
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
|
160
|
-
|
|
214
|
+
redisContextCloseFd(c);
|
|
161
215
|
return REDIS_ERR;
|
|
162
216
|
}
|
|
163
217
|
|
|
164
|
-
if (redisCheckSocketError(c
|
|
218
|
+
if (redisCheckSocketError(c) != REDIS_OK)
|
|
165
219
|
return REDIS_ERR;
|
|
166
220
|
|
|
167
221
|
return REDIS_OK;
|
|
168
222
|
}
|
|
169
223
|
|
|
170
224
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
|
171
|
-
|
|
225
|
+
redisContextCloseFd(c);
|
|
172
226
|
return REDIS_ERR;
|
|
173
227
|
}
|
|
174
228
|
|
|
175
|
-
int redisCheckSocketError(redisContext *c
|
|
229
|
+
int redisCheckSocketError(redisContext *c) {
|
|
176
230
|
int err = 0;
|
|
177
231
|
socklen_t errlen = sizeof(err);
|
|
178
232
|
|
|
179
|
-
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
|
233
|
+
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
|
|
180
234
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)");
|
|
181
|
-
close(fd);
|
|
182
235
|
return REDIS_ERR;
|
|
183
236
|
}
|
|
184
237
|
|
|
185
238
|
if (err) {
|
|
186
239
|
errno = err;
|
|
187
240
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
|
|
188
|
-
close(fd);
|
|
189
241
|
return REDIS_ERR;
|
|
190
242
|
}
|
|
191
243
|
|
|
192
244
|
return REDIS_OK;
|
|
193
245
|
}
|
|
194
246
|
|
|
195
|
-
int redisContextSetTimeout(redisContext *c, struct timeval tv) {
|
|
247
|
+
int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
|
|
196
248
|
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
|
|
197
249
|
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
|
|
198
250
|
return REDIS_ERR;
|
|
@@ -204,11 +256,53 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv) {
|
|
|
204
256
|
return REDIS_OK;
|
|
205
257
|
}
|
|
206
258
|
|
|
207
|
-
int
|
|
208
|
-
|
|
259
|
+
static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
|
260
|
+
const struct timeval *timeout,
|
|
261
|
+
const char *source_addr) {
|
|
262
|
+
int s, rv, n;
|
|
209
263
|
char _port[6]; /* strlen("65535"); */
|
|
210
|
-
struct addrinfo hints, *servinfo, *p;
|
|
264
|
+
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
|
|
211
265
|
int blocking = (c->flags & REDIS_BLOCK);
|
|
266
|
+
int reuseaddr = (c->flags & REDIS_REUSEADDR);
|
|
267
|
+
int reuses = 0;
|
|
268
|
+
|
|
269
|
+
c->connection_type = REDIS_CONN_TCP;
|
|
270
|
+
c->tcp.port = port;
|
|
271
|
+
|
|
272
|
+
/* We need to take possession of the passed parameters
|
|
273
|
+
* to make them reusable for a reconnect.
|
|
274
|
+
* We also carefully check we don't free data we already own,
|
|
275
|
+
* as in the case of the reconnect method.
|
|
276
|
+
*
|
|
277
|
+
* This is a bit ugly, but atleast it works and doesn't leak memory.
|
|
278
|
+
**/
|
|
279
|
+
if (c->tcp.host != addr) {
|
|
280
|
+
if (c->tcp.host)
|
|
281
|
+
free(c->tcp.host);
|
|
282
|
+
|
|
283
|
+
c->tcp.host = strdup(addr);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (timeout) {
|
|
287
|
+
if (c->timeout != timeout) {
|
|
288
|
+
if (c->timeout == NULL)
|
|
289
|
+
c->timeout = malloc(sizeof(struct timeval));
|
|
290
|
+
|
|
291
|
+
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
if (c->timeout)
|
|
295
|
+
free(c->timeout);
|
|
296
|
+
c->timeout = NULL;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (source_addr == NULL) {
|
|
300
|
+
free(c->tcp.source_addr);
|
|
301
|
+
c->tcp.source_addr = NULL;
|
|
302
|
+
} else if (c->tcp.source_addr != source_addr) {
|
|
303
|
+
free(c->tcp.source_addr);
|
|
304
|
+
c->tcp.source_addr = strdup(source_addr);
|
|
305
|
+
}
|
|
212
306
|
|
|
213
307
|
snprintf(_port, 6, "%d", port);
|
|
214
308
|
memset(&hints,0,sizeof(hints));
|
|
@@ -220,7 +314,7 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t
|
|
|
220
314
|
* as this would add latency to every connect. Otherwise a more sensible
|
|
221
315
|
* route could be: Use IPv6 if both addresses are available and there is IPv6
|
|
222
316
|
* connectivity. */
|
|
223
|
-
if ((rv = getaddrinfo(
|
|
317
|
+
if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) {
|
|
224
318
|
hints.ai_family = AF_INET6;
|
|
225
319
|
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
|
|
226
320
|
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
|
|
@@ -228,28 +322,67 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t
|
|
|
228
322
|
}
|
|
229
323
|
}
|
|
230
324
|
for (p = servinfo; p != NULL; p = p->ai_next) {
|
|
325
|
+
addrretry:
|
|
231
326
|
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
|
|
232
327
|
continue;
|
|
233
328
|
|
|
234
|
-
|
|
329
|
+
c->fd = s;
|
|
330
|
+
if (redisSetBlocking(c,0) != REDIS_OK)
|
|
235
331
|
goto error;
|
|
332
|
+
if (c->tcp.source_addr) {
|
|
333
|
+
int bound = 0;
|
|
334
|
+
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
|
|
335
|
+
if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) {
|
|
336
|
+
char buf[128];
|
|
337
|
+
snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
|
|
338
|
+
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
|
339
|
+
goto error;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (reuseaddr) {
|
|
343
|
+
n = 1;
|
|
344
|
+
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
|
|
345
|
+
sizeof(n)) < 0) {
|
|
346
|
+
goto error;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
for (b = bservinfo; b != NULL; b = b->ai_next) {
|
|
351
|
+
if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
|
|
352
|
+
bound = 1;
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
freeaddrinfo(bservinfo);
|
|
357
|
+
if (!bound) {
|
|
358
|
+
char buf[128];
|
|
359
|
+
snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno));
|
|
360
|
+
__redisSetError(c,REDIS_ERR_OTHER,buf);
|
|
361
|
+
goto error;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
236
364
|
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
|
|
237
365
|
if (errno == EHOSTUNREACH) {
|
|
238
|
-
|
|
366
|
+
redisContextCloseFd(c);
|
|
239
367
|
continue;
|
|
240
368
|
} else if (errno == EINPROGRESS && !blocking) {
|
|
241
369
|
/* This is ok. */
|
|
370
|
+
} else if (errno == EADDRNOTAVAIL && reuseaddr) {
|
|
371
|
+
if (++reuses >= REDIS_CONNECT_RETRIES) {
|
|
372
|
+
goto error;
|
|
373
|
+
} else {
|
|
374
|
+
goto addrretry;
|
|
375
|
+
}
|
|
242
376
|
} else {
|
|
243
|
-
if (redisContextWaitReady(c,
|
|
377
|
+
if (redisContextWaitReady(c,c->timeout) != REDIS_OK)
|
|
244
378
|
goto error;
|
|
245
379
|
}
|
|
246
380
|
}
|
|
247
|
-
if (blocking && redisSetBlocking(c,
|
|
381
|
+
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
|
248
382
|
goto error;
|
|
249
|
-
if (redisSetTcpNoDelay(c
|
|
383
|
+
if (redisSetTcpNoDelay(c) != REDIS_OK)
|
|
250
384
|
goto error;
|
|
251
385
|
|
|
252
|
-
c->fd = s;
|
|
253
386
|
c->flags |= REDIS_CONNECTED;
|
|
254
387
|
rv = REDIS_OK;
|
|
255
388
|
goto end;
|
|
@@ -268,32 +401,58 @@ end:
|
|
|
268
401
|
return rv; // Need to return REDIS_OK if alright
|
|
269
402
|
}
|
|
270
403
|
|
|
271
|
-
int
|
|
272
|
-
|
|
404
|
+
int redisContextConnectTcp(redisContext *c, const char *addr, int port,
|
|
405
|
+
const struct timeval *timeout) {
|
|
406
|
+
return _redisContextConnectTcp(c, addr, port, timeout, NULL);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
|
|
410
|
+
const struct timeval *timeout,
|
|
411
|
+
const char *source_addr) {
|
|
412
|
+
return _redisContextConnectTcp(c, addr, port, timeout, source_addr);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
|
|
273
416
|
int blocking = (c->flags & REDIS_BLOCK);
|
|
274
417
|
struct sockaddr_un sa;
|
|
275
418
|
|
|
276
|
-
if (
|
|
419
|
+
if (redisCreateSocket(c,AF_LOCAL) < 0)
|
|
277
420
|
return REDIS_ERR;
|
|
278
|
-
if (redisSetBlocking(c,
|
|
421
|
+
if (redisSetBlocking(c,0) != REDIS_OK)
|
|
279
422
|
return REDIS_ERR;
|
|
280
423
|
|
|
424
|
+
c->connection_type = REDIS_CONN_UNIX;
|
|
425
|
+
if (c->unix_sock.path != path)
|
|
426
|
+
c->unix_sock.path = strdup(path);
|
|
427
|
+
|
|
428
|
+
if (timeout) {
|
|
429
|
+
if (c->timeout != timeout) {
|
|
430
|
+
if (c->timeout == NULL)
|
|
431
|
+
c->timeout = malloc(sizeof(struct timeval));
|
|
432
|
+
|
|
433
|
+
memcpy(c->timeout, timeout, sizeof(struct timeval));
|
|
434
|
+
}
|
|
435
|
+
} else {
|
|
436
|
+
if (c->timeout)
|
|
437
|
+
free(c->timeout);
|
|
438
|
+
c->timeout = NULL;
|
|
439
|
+
}
|
|
440
|
+
|
|
281
441
|
sa.sun_family = AF_LOCAL;
|
|
282
442
|
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
|
283
|
-
if (connect(
|
|
443
|
+
if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
|
284
444
|
if (errno == EINPROGRESS && !blocking) {
|
|
285
445
|
/* This is ok. */
|
|
286
446
|
} else {
|
|
287
|
-
if (redisContextWaitReady(c,
|
|
447
|
+
if (redisContextWaitReady(c,c->timeout) != REDIS_OK)
|
|
288
448
|
return REDIS_ERR;
|
|
289
449
|
}
|
|
290
450
|
}
|
|
291
451
|
|
|
292
452
|
/* Reset socket to be blocking after connect(2). */
|
|
293
|
-
if (blocking && redisSetBlocking(c,
|
|
453
|
+
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
|
|
294
454
|
return REDIS_ERR;
|
|
295
455
|
|
|
296
|
-
c->fd = s;
|
|
297
456
|
c->flags |= REDIS_CONNECTED;
|
|
298
457
|
return REDIS_OK;
|
|
299
458
|
}
|