hiredis 0.6.1 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }