redis-client 0.2.0 → 0.4.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Gemfile +1 -2
  4. data/Gemfile.lock +2 -3
  5. data/README.md +66 -3
  6. data/Rakefile +43 -23
  7. data/lib/redis_client/command_builder.rb +83 -0
  8. data/lib/redis_client/config.rb +9 -48
  9. data/lib/redis_client/connection_mixin.rb +38 -0
  10. data/lib/redis_client/decorator.rb +84 -0
  11. data/lib/redis_client/pooled.rb +38 -30
  12. data/lib/redis_client/ruby_connection/buffered_io.rb +153 -0
  13. data/lib/redis_client/{resp3.rb → ruby_connection/resp3.rb} +0 -26
  14. data/lib/redis_client/{connection.rb → ruby_connection.rb} +26 -31
  15. data/lib/redis_client/version.rb +1 -1
  16. data/lib/redis_client.rb +162 -36
  17. data/redis-client.gemspec +2 -4
  18. metadata +12 -59
  19. data/.rubocop.yml +0 -190
  20. data/ext/redis_client/hiredis/export.clang +0 -2
  21. data/ext/redis_client/hiredis/export.gcc +0 -7
  22. data/ext/redis_client/hiredis/extconf.rb +0 -62
  23. data/ext/redis_client/hiredis/hiredis_connection.c +0 -708
  24. data/ext/redis_client/hiredis/vendor/.gitignore +0 -9
  25. data/ext/redis_client/hiredis/vendor/.travis.yml +0 -131
  26. data/ext/redis_client/hiredis/vendor/CHANGELOG.md +0 -364
  27. data/ext/redis_client/hiredis/vendor/CMakeLists.txt +0 -165
  28. data/ext/redis_client/hiredis/vendor/COPYING +0 -29
  29. data/ext/redis_client/hiredis/vendor/Makefile +0 -308
  30. data/ext/redis_client/hiredis/vendor/README.md +0 -664
  31. data/ext/redis_client/hiredis/vendor/adapters/ae.h +0 -130
  32. data/ext/redis_client/hiredis/vendor/adapters/glib.h +0 -156
  33. data/ext/redis_client/hiredis/vendor/adapters/ivykis.h +0 -84
  34. data/ext/redis_client/hiredis/vendor/adapters/libev.h +0 -179
  35. data/ext/redis_client/hiredis/vendor/adapters/libevent.h +0 -175
  36. data/ext/redis_client/hiredis/vendor/adapters/libuv.h +0 -117
  37. data/ext/redis_client/hiredis/vendor/adapters/macosx.h +0 -115
  38. data/ext/redis_client/hiredis/vendor/adapters/qt.h +0 -135
  39. data/ext/redis_client/hiredis/vendor/alloc.c +0 -86
  40. data/ext/redis_client/hiredis/vendor/alloc.h +0 -91
  41. data/ext/redis_client/hiredis/vendor/appveyor.yml +0 -24
  42. data/ext/redis_client/hiredis/vendor/async.c +0 -887
  43. data/ext/redis_client/hiredis/vendor/async.h +0 -147
  44. data/ext/redis_client/hiredis/vendor/async_private.h +0 -75
  45. data/ext/redis_client/hiredis/vendor/dict.c +0 -352
  46. data/ext/redis_client/hiredis/vendor/dict.h +0 -126
  47. data/ext/redis_client/hiredis/vendor/fmacros.h +0 -12
  48. data/ext/redis_client/hiredis/vendor/hiredis-config.cmake.in +0 -13
  49. data/ext/redis_client/hiredis/vendor/hiredis.c +0 -1174
  50. data/ext/redis_client/hiredis/vendor/hiredis.h +0 -336
  51. data/ext/redis_client/hiredis/vendor/hiredis.pc.in +0 -12
  52. data/ext/redis_client/hiredis/vendor/hiredis_ssl-config.cmake.in +0 -13
  53. data/ext/redis_client/hiredis/vendor/hiredis_ssl.h +0 -157
  54. data/ext/redis_client/hiredis/vendor/hiredis_ssl.pc.in +0 -12
  55. data/ext/redis_client/hiredis/vendor/net.c +0 -612
  56. data/ext/redis_client/hiredis/vendor/net.h +0 -56
  57. data/ext/redis_client/hiredis/vendor/read.c +0 -739
  58. data/ext/redis_client/hiredis/vendor/read.h +0 -129
  59. data/ext/redis_client/hiredis/vendor/sds.c +0 -1289
  60. data/ext/redis_client/hiredis/vendor/sds.h +0 -278
  61. data/ext/redis_client/hiredis/vendor/sdsalloc.h +0 -44
  62. data/ext/redis_client/hiredis/vendor/sockcompat.c +0 -248
  63. data/ext/redis_client/hiredis/vendor/sockcompat.h +0 -92
  64. data/ext/redis_client/hiredis/vendor/ssl.c +0 -544
  65. data/ext/redis_client/hiredis/vendor/test.c +0 -1401
  66. data/ext/redis_client/hiredis/vendor/test.sh +0 -78
  67. data/ext/redis_client/hiredis/vendor/win32.h +0 -56
  68. data/lib/redis_client/buffered_io.rb +0 -151
  69. data/lib/redis_client/hiredis_connection.rb +0 -80
@@ -1,612 +0,0 @@
1
- /* Extracted from anet.c to work properly with Hiredis error reporting.
2
- *
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>
7
- *
8
- * All rights reserved.
9
- *
10
- * Redistribution and use in source and binary forms, with or without
11
- * modification, are permitted provided that the following conditions are met:
12
- *
13
- * * Redistributions of source code must retain the above copyright notice,
14
- * this list of conditions and the following disclaimer.
15
- * * Redistributions in binary form must reproduce the above copyright
16
- * notice, this list of conditions and the following disclaimer in the
17
- * documentation and/or other materials provided with the distribution.
18
- * * Neither the name of Redis nor the names of its contributors may be used
19
- * to endorse or promote products derived from this software without
20
- * specific prior written permission.
21
- *
22
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
- * POSSIBILITY OF SUCH DAMAGE.
33
- */
34
-
35
- #include "fmacros.h"
36
- #include <sys/types.h>
37
- #include <fcntl.h>
38
- #include <string.h>
39
- #include <errno.h>
40
- #include <stdarg.h>
41
- #include <stdio.h>
42
- #include <limits.h>
43
- #include <stdlib.h>
44
-
45
- #include "net.h"
46
- #include "sds.h"
47
- #include "sockcompat.h"
48
- #include "win32.h"
49
-
50
- /* Defined in hiredis.c */
51
- void __redisSetError(redisContext *c, int type, const char *str);
52
-
53
- void redisNetClose(redisContext *c) {
54
- if (c && c->fd != REDIS_INVALID_FD) {
55
- close(c->fd);
56
- c->fd = REDIS_INVALID_FD;
57
- }
58
- }
59
-
60
- ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
61
- ssize_t nread = recv(c->fd, buf, bufcap, 0);
62
- if (nread == -1) {
63
- if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
64
- /* Try again later */
65
- return 0;
66
- } else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) {
67
- /* especially in windows */
68
- __redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout");
69
- return -1;
70
- } else {
71
- __redisSetError(c, REDIS_ERR_IO, NULL);
72
- return -1;
73
- }
74
- } else if (nread == 0) {
75
- __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
76
- return -1;
77
- } else {
78
- return nread;
79
- }
80
- }
81
-
82
- ssize_t redisNetWrite(redisContext *c) {
83
- ssize_t nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
84
- if (nwritten < 0) {
85
- if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
86
- /* Try again later */
87
- } else {
88
- __redisSetError(c, REDIS_ERR_IO, NULL);
89
- return -1;
90
- }
91
- }
92
- return nwritten;
93
- }
94
-
95
- static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
96
- int errorno = errno; /* snprintf() may change errno */
97
- char buf[128] = { 0 };
98
- size_t len = 0;
99
-
100
- if (prefix != NULL)
101
- len = snprintf(buf,sizeof(buf),"%s: ",prefix);
102
- strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len);
103
- __redisSetError(c,type,buf);
104
- }
105
-
106
- static int redisSetReuseAddr(redisContext *c) {
107
- int on = 1;
108
- if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
109
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
110
- redisNetClose(c);
111
- return REDIS_ERR;
112
- }
113
- return REDIS_OK;
114
- }
115
-
116
- static int redisCreateSocket(redisContext *c, int type) {
117
- redisFD s;
118
- if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) {
119
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
120
- return REDIS_ERR;
121
- }
122
- c->fd = s;
123
- if (type == AF_INET) {
124
- if (redisSetReuseAddr(c) == REDIS_ERR) {
125
- return REDIS_ERR;
126
- }
127
- }
128
- return REDIS_OK;
129
- }
130
-
131
- static int redisSetBlocking(redisContext *c, int blocking) {
132
- #ifndef _WIN32
133
- int flags;
134
-
135
- /* Set the socket nonblocking.
136
- * Note that fcntl(2) for F_GETFL and F_SETFL can't be
137
- * interrupted by a signal. */
138
- if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
139
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
140
- redisNetClose(c);
141
- return REDIS_ERR;
142
- }
143
-
144
- if (blocking)
145
- flags &= ~O_NONBLOCK;
146
- else
147
- flags |= O_NONBLOCK;
148
-
149
- if (fcntl(c->fd, F_SETFL, flags) == -1) {
150
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
151
- redisNetClose(c);
152
- return REDIS_ERR;
153
- }
154
- #else
155
- u_long mode = blocking ? 0 : 1;
156
- if (ioctl(c->fd, FIONBIO, &mode) == -1) {
157
- __redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)");
158
- redisNetClose(c);
159
- return REDIS_ERR;
160
- }
161
- #endif /* _WIN32 */
162
- return REDIS_OK;
163
- }
164
-
165
- int redisKeepAlive(redisContext *c, int interval) {
166
- int val = 1;
167
- redisFD fd = c->fd;
168
-
169
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
170
- __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
171
- return REDIS_ERR;
172
- }
173
-
174
- val = interval;
175
-
176
- #if defined(__APPLE__) && defined(__MACH__)
177
- if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
178
- __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
179
- return REDIS_ERR;
180
- }
181
- #else
182
- #if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
183
- if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
184
- __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
185
- return REDIS_ERR;
186
- }
187
-
188
- val = interval/3;
189
- if (val == 0) val = 1;
190
- if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
191
- __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
192
- return REDIS_ERR;
193
- }
194
-
195
- val = 3;
196
- if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
197
- __redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
198
- return REDIS_ERR;
199
- }
200
- #endif
201
- #endif
202
-
203
- return REDIS_OK;
204
- }
205
-
206
- int redisSetTcpNoDelay(redisContext *c) {
207
- int yes = 1;
208
- if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
209
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
210
- redisNetClose(c);
211
- return REDIS_ERR;
212
- }
213
- return REDIS_OK;
214
- }
215
-
216
- #define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
217
-
218
- static int redisContextTimeoutMsec(redisContext *c, long *result)
219
- {
220
- const struct timeval *timeout = c->connect_timeout;
221
- long msec = -1;
222
-
223
- /* Only use timeout when not NULL. */
224
- if (timeout != NULL) {
225
- if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
226
- *result = msec;
227
- return REDIS_ERR;
228
- }
229
-
230
- msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000);
231
-
232
- if (msec < 0 || msec > INT_MAX) {
233
- msec = INT_MAX;
234
- }
235
- }
236
-
237
- *result = msec;
238
- return REDIS_OK;
239
- }
240
-
241
- static int redisContextWaitReady(redisContext *c, long msec) {
242
- struct pollfd wfd[1];
243
-
244
- wfd[0].fd = c->fd;
245
- wfd[0].events = POLLOUT;
246
-
247
- if (errno == EINPROGRESS) {
248
- int res;
249
-
250
- if ((res = poll(wfd, 1, msec)) == -1) {
251
- __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
252
- redisNetClose(c);
253
- return REDIS_ERR;
254
- } else if (res == 0) {
255
- errno = ETIMEDOUT;
256
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
257
- redisNetClose(c);
258
- return REDIS_ERR;
259
- }
260
-
261
- if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
262
- redisCheckSocketError(c);
263
- return REDIS_ERR;
264
- }
265
-
266
- return REDIS_OK;
267
- }
268
-
269
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
270
- redisNetClose(c);
271
- return REDIS_ERR;
272
- }
273
-
274
- int redisCheckConnectDone(redisContext *c, int *completed) {
275
- int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen);
276
- if (rc == 0) {
277
- *completed = 1;
278
- return REDIS_OK;
279
- }
280
- switch (errno) {
281
- case EISCONN:
282
- *completed = 1;
283
- return REDIS_OK;
284
- case EALREADY:
285
- case EINPROGRESS:
286
- case EWOULDBLOCK:
287
- *completed = 0;
288
- return REDIS_OK;
289
- default:
290
- return REDIS_ERR;
291
- }
292
- }
293
-
294
- int redisCheckSocketError(redisContext *c) {
295
- int err = 0, errno_saved = errno;
296
- socklen_t errlen = sizeof(err);
297
-
298
- if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
299
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)");
300
- return REDIS_ERR;
301
- }
302
-
303
- if (err == 0) {
304
- err = errno_saved;
305
- }
306
-
307
- if (err) {
308
- errno = err;
309
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
310
- return REDIS_ERR;
311
- }
312
-
313
- return REDIS_OK;
314
- }
315
-
316
- int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
317
- const void *to_ptr = &tv;
318
- size_t to_sz = sizeof(tv);
319
-
320
- if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
321
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
322
- return REDIS_ERR;
323
- }
324
- if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) {
325
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");
326
- return REDIS_ERR;
327
- }
328
- return REDIS_OK;
329
- }
330
-
331
- int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) {
332
- /* Same timeval struct, short circuit */
333
- if (c->connect_timeout == timeout)
334
- return REDIS_OK;
335
-
336
- /* Allocate context timeval if we need to */
337
- if (c->connect_timeout == NULL) {
338
- c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout));
339
- if (c->connect_timeout == NULL)
340
- return REDIS_ERR;
341
- }
342
-
343
- memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout));
344
- return REDIS_OK;
345
- }
346
-
347
- int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) {
348
- /* Same timeval struct, short circuit */
349
- if (c->command_timeout == timeout)
350
- return REDIS_OK;
351
-
352
- /* Allocate context timeval if we need to */
353
- if (c->command_timeout == NULL) {
354
- c->command_timeout = hi_malloc(sizeof(*c->command_timeout));
355
- if (c->command_timeout == NULL)
356
- return REDIS_ERR;
357
- }
358
-
359
- memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout));
360
- return REDIS_OK;
361
- }
362
-
363
- static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
364
- const struct timeval *timeout,
365
- const char *source_addr) {
366
- redisFD s;
367
- int rv, n;
368
- char _port[6]; /* strlen("65535"); */
369
- struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
370
- int blocking = (c->flags & REDIS_BLOCK);
371
- int reuseaddr = (c->flags & REDIS_REUSEADDR);
372
- int reuses = 0;
373
- long timeout_msec = -1;
374
-
375
- servinfo = NULL;
376
- c->connection_type = REDIS_CONN_TCP;
377
- c->tcp.port = port;
378
-
379
- /* We need to take possession of the passed parameters
380
- * to make them reusable for a reconnect.
381
- * We also carefully check we don't free data we already own,
382
- * as in the case of the reconnect method.
383
- *
384
- * This is a bit ugly, but atleast it works and doesn't leak memory.
385
- **/
386
- if (c->tcp.host != addr) {
387
- hi_free(c->tcp.host);
388
-
389
- c->tcp.host = hi_strdup(addr);
390
- if (c->tcp.host == NULL)
391
- goto oom;
392
- }
393
-
394
- if (timeout) {
395
- if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
396
- goto oom;
397
- } else {
398
- hi_free(c->connect_timeout);
399
- c->connect_timeout = NULL;
400
- }
401
-
402
- if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
403
- __redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified");
404
- goto error;
405
- }
406
-
407
- if (source_addr == NULL) {
408
- hi_free(c->tcp.source_addr);
409
- c->tcp.source_addr = NULL;
410
- } else if (c->tcp.source_addr != source_addr) {
411
- hi_free(c->tcp.source_addr);
412
- c->tcp.source_addr = hi_strdup(source_addr);
413
- }
414
-
415
- snprintf(_port, 6, "%d", port);
416
- memset(&hints,0,sizeof(hints));
417
- hints.ai_family = AF_INET;
418
- hints.ai_socktype = SOCK_STREAM;
419
-
420
- /* Try with IPv6 if no IPv4 address was found. We do it in this order since
421
- * in a Redis client you can't afford to test if you have IPv6 connectivity
422
- * as this would add latency to every connect. Otherwise a more sensible
423
- * route could be: Use IPv6 if both addresses are available and there is IPv6
424
- * connectivity. */
425
- if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) {
426
- hints.ai_family = AF_INET6;
427
- if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
428
- __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
429
- return REDIS_ERR;
430
- }
431
- }
432
- for (p = servinfo; p != NULL; p = p->ai_next) {
433
- addrretry:
434
- if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD)
435
- continue;
436
-
437
- c->fd = s;
438
- if (redisSetBlocking(c,0) != REDIS_OK)
439
- goto error;
440
- if (c->tcp.source_addr) {
441
- int bound = 0;
442
- /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
443
- if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) {
444
- char buf[128];
445
- snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
446
- __redisSetError(c,REDIS_ERR_OTHER,buf);
447
- goto error;
448
- }
449
-
450
- if (reuseaddr) {
451
- n = 1;
452
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
453
- sizeof(n)) < 0) {
454
- freeaddrinfo(bservinfo);
455
- goto error;
456
- }
457
- }
458
-
459
- for (b = bservinfo; b != NULL; b = b->ai_next) {
460
- if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
461
- bound = 1;
462
- break;
463
- }
464
- }
465
- freeaddrinfo(bservinfo);
466
- if (!bound) {
467
- char buf[128];
468
- snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno));
469
- __redisSetError(c,REDIS_ERR_OTHER,buf);
470
- goto error;
471
- }
472
- }
473
-
474
- /* For repeat connection */
475
- hi_free(c->saddr);
476
- c->saddr = hi_malloc(p->ai_addrlen);
477
- if (c->saddr == NULL)
478
- goto oom;
479
-
480
- memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
481
- c->addrlen = p->ai_addrlen;
482
-
483
- if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
484
- if (errno == EHOSTUNREACH) {
485
- redisNetClose(c);
486
- continue;
487
- } else if (errno == EINPROGRESS) {
488
- if (blocking) {
489
- goto wait_for_ready;
490
- }
491
- /* This is ok.
492
- * Note that even when it's in blocking mode, we unset blocking
493
- * for `connect()`
494
- */
495
- } else if (errno == EADDRNOTAVAIL && reuseaddr) {
496
- if (++reuses >= REDIS_CONNECT_RETRIES) {
497
- goto error;
498
- } else {
499
- redisNetClose(c);
500
- goto addrretry;
501
- }
502
- } else {
503
- wait_for_ready:
504
- if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
505
- goto error;
506
- if (redisSetTcpNoDelay(c) != REDIS_OK)
507
- goto error;
508
- }
509
- }
510
- if (blocking && redisSetBlocking(c,1) != REDIS_OK)
511
- goto error;
512
-
513
- c->flags |= REDIS_CONNECTED;
514
- rv = REDIS_OK;
515
- goto end;
516
- }
517
- if (p == NULL) {
518
- char buf[128];
519
- snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno));
520
- __redisSetError(c,REDIS_ERR_OTHER,buf);
521
- goto error;
522
- }
523
-
524
- oom:
525
- __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
526
- error:
527
- rv = REDIS_ERR;
528
- end:
529
- if(servinfo) {
530
- freeaddrinfo(servinfo);
531
- }
532
-
533
- return rv; // Need to return REDIS_OK if alright
534
- }
535
-
536
- int redisContextConnectTcp(redisContext *c, const char *addr, int port,
537
- const struct timeval *timeout) {
538
- return _redisContextConnectTcp(c, addr, port, timeout, NULL);
539
- }
540
-
541
- int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
542
- const struct timeval *timeout,
543
- const char *source_addr) {
544
- return _redisContextConnectTcp(c, addr, port, timeout, source_addr);
545
- }
546
-
547
- int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
548
- #ifndef _WIN32
549
- int blocking = (c->flags & REDIS_BLOCK);
550
- struct sockaddr_un *sa;
551
- long timeout_msec = -1;
552
-
553
- if (redisCreateSocket(c,AF_UNIX) < 0)
554
- return REDIS_ERR;
555
- if (redisSetBlocking(c,0) != REDIS_OK)
556
- return REDIS_ERR;
557
-
558
- c->connection_type = REDIS_CONN_UNIX;
559
- if (c->unix_sock.path != path) {
560
- hi_free(c->unix_sock.path);
561
-
562
- c->unix_sock.path = hi_strdup(path);
563
- if (c->unix_sock.path == NULL)
564
- goto oom;
565
- }
566
-
567
- if (timeout) {
568
- if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR)
569
- goto oom;
570
- } else {
571
- hi_free(c->connect_timeout);
572
- c->connect_timeout = NULL;
573
- }
574
-
575
- if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
576
- return REDIS_ERR;
577
-
578
- /* Don't leak sockaddr if we're reconnecting */
579
- if (c->saddr) hi_free(c->saddr);
580
-
581
- sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un)));
582
- if (sa == NULL)
583
- goto oom;
584
-
585
- c->addrlen = sizeof(struct sockaddr_un);
586
- sa->sun_family = AF_UNIX;
587
- strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);
588
- if (connect(c->fd, (struct sockaddr*)sa, sizeof(*sa)) == -1) {
589
- if (errno == EINPROGRESS && !blocking) {
590
- /* This is ok. */
591
- } else {
592
- if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
593
- return REDIS_ERR;
594
- }
595
- }
596
-
597
- /* Reset socket to be blocking after connect(2). */
598
- if (blocking && redisSetBlocking(c,1) != REDIS_OK)
599
- return REDIS_ERR;
600
-
601
- c->flags |= REDIS_CONNECTED;
602
- return REDIS_OK;
603
- #else
604
- /* We currently do not support Unix sockets for Windows. */
605
- /* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */
606
- errno = EPROTONOSUPPORT;
607
- return REDIS_ERR;
608
- #endif /* _WIN32 */
609
- oom:
610
- __redisSetError(c, REDIS_ERR_OOM, "Out of memory");
611
- return REDIS_ERR;
612
- }
@@ -1,56 +0,0 @@
1
- /* Extracted from anet.c to work properly with Hiredis error reporting.
2
- *
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>
7
- *
8
- * All rights reserved.
9
- *
10
- * Redistribution and use in source and binary forms, with or without
11
- * modification, are permitted provided that the following conditions are met:
12
- *
13
- * * Redistributions of source code must retain the above copyright notice,
14
- * this list of conditions and the following disclaimer.
15
- * * Redistributions in binary form must reproduce the above copyright
16
- * notice, this list of conditions and the following disclaimer in the
17
- * documentation and/or other materials provided with the distribution.
18
- * * Neither the name of Redis nor the names of its contributors may be used
19
- * to endorse or promote products derived from this software without
20
- * specific prior written permission.
21
- *
22
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
- * POSSIBILITY OF SUCH DAMAGE.
33
- */
34
-
35
- #ifndef __NET_H
36
- #define __NET_H
37
-
38
- #include "hiredis.h"
39
-
40
- void redisNetClose(redisContext *c);
41
- ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap);
42
- ssize_t redisNetWrite(redisContext *c);
43
-
44
- int redisCheckSocketError(redisContext *c);
45
- int redisContextSetTimeout(redisContext *c, const struct timeval tv);
46
- int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
47
- int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
48
- const struct timeval *timeout,
49
- const char *source_addr);
50
- int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
51
- int redisKeepAlive(redisContext *c, int interval);
52
- int redisCheckConnectDone(redisContext *c, int *completed);
53
-
54
- int redisSetTcpNoDelay(redisContext *c);
55
-
56
- #endif