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.
@@ -1,6 +1,8 @@
1
1
  /*
2
2
  * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
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
- if (r->element[j] != NULL)
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
- if (r->str != NULL)
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, "$%T\r\n", len);
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
- __redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
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
- if (c->obuf != NULL)
616
- sdsfree(c->obuf);
617
- if (c->reader != NULL)
618
- redisReaderFree(c->reader);
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
- * succesfully written to the socket. When the buffer is empty after the
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 occured trying to write and sets
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 succesfully retrieved. Returns NULL
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
  }
@@ -1,6 +1,8 @@
1
1
  /*
2
2
  * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
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 12
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
- int len; /* Length of string */
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) 2006-2011, Salvatore Sanfilippo <antirez at gmail dot com>
4
- * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
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
- __redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len);
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
- #ifdef _OSX
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 redisContextWaitReady(redisContext *c, const struct timeval *timeout) {
179
- struct pollfd wfd[1];
180
- long msec;
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
- __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL);
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(addr,_port,&hints,&servinfo)) != 0) {
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,timeout) != REDIS_OK)
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
- freeaddrinfo(servinfo);
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,AF_LOCAL) < 0)
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
- sa.sun_family = AF_LOCAL;
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,timeout) != REDIS_OK)
466
+ if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
390
467
  return REDIS_ERR;
391
468
  }
392
469
  }