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.
data/deps/hiredis/async.h CHANGED
@@ -102,6 +102,9 @@ typedef struct redisAsyncContext {
102
102
 
103
103
  /* Functions that proxy to hiredis */
104
104
  redisAsyncContext *redisAsyncConnect(const char *ip, int port);
105
+ redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
106
+ redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
107
+ const char *source_addr);
105
108
  redisAsyncContext *redisAsyncConnectUnix(const char *path);
106
109
  int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
107
110
  int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
@@ -117,6 +120,7 @@ void redisAsyncHandleWrite(redisAsyncContext *ac);
117
120
  int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
118
121
  int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
119
122
  int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
123
+ int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len);
120
124
 
121
125
  #ifdef __cplusplus
122
126
  }
@@ -1,8 +1,9 @@
1
1
  #ifndef __HIREDIS_FMACRO_H
2
2
  #define __HIREDIS_FMACRO_H
3
3
 
4
- #if !defined(_BSD_SOURCE)
4
+ #if defined(__linux__)
5
5
  #define _BSD_SOURCE
6
+ #define _DEFAULT_SOURCE
6
7
  #endif
7
8
 
8
9
  #if defined(__sun__)
@@ -13,4 +14,8 @@
13
14
  #define _XOPEN_SOURCE
14
15
  #endif
15
16
 
17
+ #if __APPLE__ && __MACH__
18
+ #define _OSX
19
+ #endif
20
+
16
21
  #endif
@@ -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
  *
@@ -73,6 +75,9 @@ void freeReplyObject(void *reply) {
73
75
  redisReply *r = reply;
74
76
  size_t j;
75
77
 
78
+ if (r == NULL)
79
+ return;
80
+
76
81
  switch(r->type) {
77
82
  case REDIS_REPLY_INTEGER:
78
83
  break; /* Nothing to free */
@@ -183,504 +188,23 @@ static void *createNilObject(const redisReadTask *task) {
183
188
  return r;
184
189
  }
185
190
 
186
- static void __redisReaderSetError(redisReader *r, int type, const char *str) {
187
- size_t len;
188
-
189
- if (r->reply != NULL && r->fn && r->fn->freeObject) {
190
- r->fn->freeObject(r->reply);
191
- r->reply = NULL;
192
- }
193
-
194
- /* Clear input buffer on errors. */
195
- if (r->buf != NULL) {
196
- sdsfree(r->buf);
197
- r->buf = NULL;
198
- r->pos = r->len = 0;
199
- }
200
-
201
- /* Reset task stack. */
202
- r->ridx = -1;
203
-
204
- /* Set error. */
205
- r->err = type;
206
- len = strlen(str);
207
- len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
208
- memcpy(r->errstr,str,len);
209
- r->errstr[len] = '\0';
210
- }
211
-
212
- static size_t chrtos(char *buf, size_t size, char byte) {
213
- size_t len = 0;
214
-
215
- switch(byte) {
216
- case '\\':
217
- case '"':
218
- len = snprintf(buf,size,"\"\\%c\"",byte);
219
- break;
220
- case '\n': len = snprintf(buf,size,"\"\\n\""); break;
221
- case '\r': len = snprintf(buf,size,"\"\\r\""); break;
222
- case '\t': len = snprintf(buf,size,"\"\\t\""); break;
223
- case '\a': len = snprintf(buf,size,"\"\\a\""); break;
224
- case '\b': len = snprintf(buf,size,"\"\\b\""); break;
225
- default:
226
- if (isprint(byte))
227
- len = snprintf(buf,size,"\"%c\"",byte);
228
- else
229
- len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
230
- break;
231
- }
232
-
233
- return len;
234
- }
235
-
236
- static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
237
- char cbuf[8], sbuf[128];
238
-
239
- chrtos(cbuf,sizeof(cbuf),byte);
240
- snprintf(sbuf,sizeof(sbuf),
241
- "Protocol error, got %s as reply type byte", cbuf);
242
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
243
- }
244
-
245
- static void __redisReaderSetErrorOOM(redisReader *r) {
246
- __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
247
- }
248
-
249
- static char *readBytes(redisReader *r, unsigned int bytes) {
250
- char *p;
251
- if (r->len-r->pos >= bytes) {
252
- p = r->buf+r->pos;
253
- r->pos += bytes;
254
- return p;
255
- }
256
- return NULL;
257
- }
258
-
259
- /* Find pointer to \r\n. */
260
- static char *seekNewline(char *s, size_t len) {
261
- int pos = 0;
262
- int _len = len-1;
263
-
264
- /* Position should be < len-1 because the character at "pos" should be
265
- * followed by a \n. Note that strchr cannot be used because it doesn't
266
- * allow to search a limited length and the buffer that is being searched
267
- * might not have a trailing NULL character. */
268
- while (pos < _len) {
269
- while(pos < _len && s[pos] != '\r') pos++;
270
- if (s[pos] != '\r') {
271
- /* Not found. */
272
- return NULL;
273
- } else {
274
- if (s[pos+1] == '\n') {
275
- /* Found. */
276
- return s+pos;
277
- } else {
278
- /* Continue searching. */
279
- pos++;
280
- }
281
- }
282
- }
283
- return NULL;
284
- }
285
-
286
- /* Read a long long value starting at *s, under the assumption that it will be
287
- * terminated by \r\n. Ambiguously returns -1 for unexpected input. */
288
- static long long readLongLong(char *s) {
289
- long long v = 0;
290
- int dec, mult = 1;
291
- char c;
292
-
293
- if (*s == '-') {
294
- mult = -1;
295
- s++;
296
- } else if (*s == '+') {
297
- mult = 1;
298
- s++;
299
- }
300
-
301
- while ((c = *(s++)) != '\r') {
302
- dec = c - '0';
303
- if (dec >= 0 && dec < 10) {
304
- v *= 10;
305
- v += dec;
306
- } else {
307
- /* Should not happen... */
308
- return -1;
309
- }
310
- }
311
-
312
- return mult*v;
313
- }
314
-
315
- static char *readLine(redisReader *r, int *_len) {
316
- char *p, *s;
317
- int len;
318
-
319
- p = r->buf+r->pos;
320
- s = seekNewline(p,(r->len-r->pos));
321
- if (s != NULL) {
322
- len = s-(r->buf+r->pos);
323
- r->pos += len+2; /* skip \r\n */
324
- if (_len) *_len = len;
325
- return p;
326
- }
327
- return NULL;
328
- }
329
-
330
- static void moveToNextTask(redisReader *r) {
331
- redisReadTask *cur, *prv;
332
- while (r->ridx >= 0) {
333
- /* Return a.s.a.p. when the stack is now empty. */
334
- if (r->ridx == 0) {
335
- r->ridx--;
336
- return;
337
- }
338
-
339
- cur = &(r->rstack[r->ridx]);
340
- prv = &(r->rstack[r->ridx-1]);
341
- assert(prv->type == REDIS_REPLY_ARRAY);
342
- if (cur->idx == prv->elements-1) {
343
- r->ridx--;
344
- } else {
345
- /* Reset the type because the next item can be anything */
346
- assert(cur->idx < prv->elements);
347
- cur->type = -1;
348
- cur->elements = -1;
349
- cur->idx++;
350
- return;
351
- }
352
- }
353
- }
354
-
355
- static int processLineItem(redisReader *r) {
356
- redisReadTask *cur = &(r->rstack[r->ridx]);
357
- void *obj;
358
- char *p;
359
- int len;
360
-
361
- if ((p = readLine(r,&len)) != NULL) {
362
- if (cur->type == REDIS_REPLY_INTEGER) {
363
- if (r->fn && r->fn->createInteger)
364
- obj = r->fn->createInteger(cur,readLongLong(p));
365
- else
366
- obj = (void*)REDIS_REPLY_INTEGER;
367
- } else {
368
- /* Type will be error or status. */
369
- if (r->fn && r->fn->createString)
370
- obj = r->fn->createString(cur,p,len);
371
- else
372
- obj = (void*)(size_t)(cur->type);
373
- }
374
-
375
- if (obj == NULL) {
376
- __redisReaderSetErrorOOM(r);
377
- return REDIS_ERR;
378
- }
379
-
380
- /* Set reply if this is the root object. */
381
- if (r->ridx == 0) r->reply = obj;
382
- moveToNextTask(r);
383
- return REDIS_OK;
384
- }
385
-
386
- return REDIS_ERR;
387
- }
388
-
389
- static int processBulkItem(redisReader *r) {
390
- redisReadTask *cur = &(r->rstack[r->ridx]);
391
- void *obj = NULL;
392
- char *p, *s;
393
- long len;
394
- unsigned long bytelen;
395
- int success = 0;
396
-
397
- p = r->buf+r->pos;
398
- s = seekNewline(p,r->len-r->pos);
399
- if (s != NULL) {
400
- p = r->buf+r->pos;
401
- bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
402
- len = readLongLong(p);
403
-
404
- if (len < 0) {
405
- /* The nil object can always be created. */
406
- if (r->fn && r->fn->createNil)
407
- obj = r->fn->createNil(cur);
408
- else
409
- obj = (void*)REDIS_REPLY_NIL;
410
- success = 1;
411
- } else {
412
- /* Only continue when the buffer contains the entire bulk item. */
413
- bytelen += len+2; /* include \r\n */
414
- if (r->pos+bytelen <= r->len) {
415
- if (r->fn && r->fn->createString)
416
- obj = r->fn->createString(cur,s+2,len);
417
- else
418
- obj = (void*)REDIS_REPLY_STRING;
419
- success = 1;
420
- }
421
- }
422
-
423
- /* Proceed when obj was created. */
424
- if (success) {
425
- if (obj == NULL) {
426
- __redisReaderSetErrorOOM(r);
427
- return REDIS_ERR;
428
- }
429
-
430
- r->pos += bytelen;
431
-
432
- /* Set reply if this is the root object. */
433
- if (r->ridx == 0) r->reply = obj;
434
- moveToNextTask(r);
435
- return REDIS_OK;
436
- }
437
- }
438
-
439
- return REDIS_ERR;
440
- }
441
-
442
- static int processMultiBulkItem(redisReader *r) {
443
- redisReadTask *cur = &(r->rstack[r->ridx]);
444
- void *obj;
445
- char *p;
446
- long elements;
447
- int root = 0;
448
-
449
- /* Set error for nested multi bulks with depth > 7 */
450
- if (r->ridx == 8) {
451
- __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
452
- "No support for nested multi bulk replies with depth > 7");
453
- return REDIS_ERR;
454
- }
455
-
456
- if ((p = readLine(r,NULL)) != NULL) {
457
- elements = readLongLong(p);
458
- root = (r->ridx == 0);
459
-
460
- if (elements == -1) {
461
- if (r->fn && r->fn->createNil)
462
- obj = r->fn->createNil(cur);
463
- else
464
- obj = (void*)REDIS_REPLY_NIL;
465
-
466
- if (obj == NULL) {
467
- __redisReaderSetErrorOOM(r);
468
- return REDIS_ERR;
469
- }
470
-
471
- moveToNextTask(r);
472
- } else {
473
- if (r->fn && r->fn->createArray)
474
- obj = r->fn->createArray(cur,elements);
475
- else
476
- obj = (void*)REDIS_REPLY_ARRAY;
477
-
478
- if (obj == NULL) {
479
- __redisReaderSetErrorOOM(r);
480
- return REDIS_ERR;
481
- }
482
-
483
- /* Modify task stack when there are more than 0 elements. */
484
- if (elements > 0) {
485
- cur->elements = elements;
486
- cur->obj = obj;
487
- r->ridx++;
488
- r->rstack[r->ridx].type = -1;
489
- r->rstack[r->ridx].elements = -1;
490
- r->rstack[r->ridx].idx = 0;
491
- r->rstack[r->ridx].obj = NULL;
492
- r->rstack[r->ridx].parent = cur;
493
- r->rstack[r->ridx].privdata = r->privdata;
494
- } else {
495
- moveToNextTask(r);
496
- }
497
- }
498
-
499
- /* Set reply if this is the root object. */
500
- if (root) r->reply = obj;
501
- return REDIS_OK;
502
- }
503
-
504
- return REDIS_ERR;
505
- }
506
-
507
- static int processItem(redisReader *r) {
508
- redisReadTask *cur = &(r->rstack[r->ridx]);
509
- char *p;
510
-
511
- /* check if we need to read type */
512
- if (cur->type < 0) {
513
- if ((p = readBytes(r,1)) != NULL) {
514
- switch (p[0]) {
515
- case '-':
516
- cur->type = REDIS_REPLY_ERROR;
517
- break;
518
- case '+':
519
- cur->type = REDIS_REPLY_STATUS;
520
- break;
521
- case ':':
522
- cur->type = REDIS_REPLY_INTEGER;
523
- break;
524
- case '$':
525
- cur->type = REDIS_REPLY_STRING;
526
- break;
527
- case '*':
528
- cur->type = REDIS_REPLY_ARRAY;
529
- break;
530
- default:
531
- __redisReaderSetErrorProtocolByte(r,*p);
532
- return REDIS_ERR;
533
- }
534
- } else {
535
- /* could not consume 1 byte */
536
- return REDIS_ERR;
537
- }
538
- }
539
-
540
- /* process typed item */
541
- switch(cur->type) {
542
- case REDIS_REPLY_ERROR:
543
- case REDIS_REPLY_STATUS:
544
- case REDIS_REPLY_INTEGER:
545
- return processLineItem(r);
546
- case REDIS_REPLY_STRING:
547
- return processBulkItem(r);
548
- case REDIS_REPLY_ARRAY:
549
- return processMultiBulkItem(r);
550
- default:
551
- assert(NULL);
552
- return REDIS_ERR; /* Avoid warning. */
553
- }
554
- }
555
-
556
- redisReader *redisReaderCreate(void) {
557
- redisReader *r;
558
-
559
- r = calloc(sizeof(redisReader),1);
560
- if (r == NULL)
561
- return NULL;
562
-
563
- r->err = 0;
564
- r->errstr[0] = '\0';
565
- r->fn = &defaultFunctions;
566
- r->buf = sdsempty();
567
- r->maxbuf = REDIS_READER_MAX_BUF;
568
- if (r->buf == NULL) {
569
- free(r);
570
- return NULL;
571
- }
572
-
573
- r->ridx = -1;
574
- return r;
575
- }
576
-
577
- void redisReaderFree(redisReader *r) {
578
- if (r->reply != NULL && r->fn && r->fn->freeObject)
579
- r->fn->freeObject(r->reply);
580
- if (r->buf != NULL)
581
- sdsfree(r->buf);
582
- free(r);
583
- }
584
-
585
- int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
586
- sds newbuf;
587
-
588
- /* Return early when this reader is in an erroneous state. */
589
- if (r->err)
590
- return REDIS_ERR;
591
-
592
- /* Copy the provided buffer. */
593
- if (buf != NULL && len >= 1) {
594
- /* Destroy internal buffer when it is empty and is quite large. */
595
- if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
596
- sdsfree(r->buf);
597
- r->buf = sdsempty();
598
- r->pos = 0;
599
-
600
- /* r->buf should not be NULL since we just free'd a larger one. */
601
- assert(r->buf != NULL);
602
- }
603
-
604
- newbuf = sdscatlen(r->buf,buf,len);
605
- if (newbuf == NULL) {
606
- __redisReaderSetErrorOOM(r);
607
- return REDIS_ERR;
608
- }
609
-
610
- r->buf = newbuf;
611
- r->len = sdslen(r->buf);
612
- }
613
-
614
- return REDIS_OK;
615
- }
616
-
617
- int redisReaderGetReply(redisReader *r, void **reply) {
618
- /* Default target pointer to NULL. */
619
- if (reply != NULL)
620
- *reply = NULL;
621
-
622
- /* Return early when this reader is in an erroneous state. */
623
- if (r->err)
624
- return REDIS_ERR;
625
-
626
- /* When the buffer is empty, there will never be a reply. */
627
- if (r->len == 0)
628
- return REDIS_OK;
629
-
630
- /* Set first item to process when the stack is empty. */
631
- if (r->ridx == -1) {
632
- r->rstack[0].type = -1;
633
- r->rstack[0].elements = -1;
634
- r->rstack[0].idx = -1;
635
- r->rstack[0].obj = NULL;
636
- r->rstack[0].parent = NULL;
637
- r->rstack[0].privdata = r->privdata;
638
- r->ridx = 0;
639
- }
640
-
641
- /* Process items in reply. */
642
- while (r->ridx >= 0)
643
- if (processItem(r) != REDIS_OK)
644
- break;
645
-
646
- /* Return ASAP when an error occurred. */
647
- if (r->err)
648
- return REDIS_ERR;
649
-
650
- /* Discard part of the buffer when we've consumed at least 1k, to avoid
651
- * doing unnecessary calls to memmove() in sds.c. */
652
- if (r->pos >= 1024) {
653
- sdsrange(r->buf,r->pos,-1);
654
- r->pos = 0;
655
- r->len = sdslen(r->buf);
656
- }
657
-
658
- /* Emit a reply when there is one. */
659
- if (r->ridx == -1) {
660
- if (reply != NULL)
661
- *reply = r->reply;
662
- r->reply = NULL;
663
- }
664
- return REDIS_OK;
665
- }
666
-
667
- /* Calculate the number of bytes needed to represent an integer as string. */
668
- static int intlen(int i) {
669
- int len = 0;
670
- if (i < 0) {
671
- len++;
672
- i = -i;
673
- }
674
- do {
675
- len++;
676
- i /= 10;
677
- } while(i);
678
- return len;
191
+ /* Return the number of digits of 'v' when converted to string in radix 10.
192
+ * Implementation borrowed from link in redis/src/util.c:string2ll(). */
193
+ static uint32_t countDigits(uint64_t v) {
194
+ uint32_t result = 1;
195
+ for (;;) {
196
+ if (v < 10) return result;
197
+ if (v < 100) return result + 1;
198
+ if (v < 1000) return result + 2;
199
+ if (v < 10000) return result + 3;
200
+ v /= 10000U;
201
+ result += 4;
202
+ }
679
203
  }
680
204
 
681
205
  /* Helper that calculates the bulk length given a certain string length. */
682
206
  static size_t bulklen(size_t len) {
683
- return 1+intlen(len)+2+len+2;
207
+ return 1+countDigits(len)+2+len+2;
684
208
  }
685
209
 
686
210
  int redisvFormatCommand(char **target, const char *format, va_list ap) {
@@ -692,6 +216,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
692
216
  char **curargv = NULL, **newargv = NULL;
693
217
  int argc = 0;
694
218
  int totlen = 0;
219
+ int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */
695
220
  int j;
696
221
 
697
222
  /* Abort if there is not target to set */
@@ -708,19 +233,19 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
708
233
  if (*c == ' ') {
709
234
  if (touched) {
710
235
  newargv = realloc(curargv,sizeof(char*)*(argc+1));
711
- if (newargv == NULL) goto err;
236
+ if (newargv == NULL) goto memory_err;
712
237
  curargv = newargv;
713
238
  curargv[argc++] = curarg;
714
239
  totlen += bulklen(sdslen(curarg));
715
240
 
716
241
  /* curarg is put in argv so it can be overwritten. */
717
242
  curarg = sdsempty();
718
- if (curarg == NULL) goto err;
243
+ if (curarg == NULL) goto memory_err;
719
244
  touched = 0;
720
245
  }
721
246
  } else {
722
247
  newarg = sdscatlen(curarg,c,1);
723
- if (newarg == NULL) goto err;
248
+ if (newarg == NULL) goto memory_err;
724
249
  curarg = newarg;
725
250
  touched = 1;
726
251
  }
@@ -751,17 +276,14 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
751
276
  /* Try to detect printf format */
752
277
  {
753
278
  static const char intfmts[] = "diouxX";
279
+ static const char flags[] = "#0-+ ";
754
280
  char _format[16];
755
281
  const char *_p = c+1;
756
282
  size_t _l = 0;
757
283
  va_list _cpy;
758
284
 
759
285
  /* Flags */
760
- if (*_p != '\0' && *_p == '#') _p++;
761
- if (*_p != '\0' && *_p == '0') _p++;
762
- if (*_p != '\0' && *_p == '-') _p++;
763
- if (*_p != '\0' && *_p == ' ') _p++;
764
- if (*_p != '\0' && *_p == '+') _p++;
286
+ while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++;
765
287
 
766
288
  /* Field width */
767
289
  while (*_p != '\0' && isdigit(*_p)) _p++;
@@ -829,7 +351,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
829
351
 
830
352
  fmt_invalid:
831
353
  va_end(_cpy);
832
- goto err;
354
+ goto format_err;
833
355
 
834
356
  fmt_valid:
835
357
  _l = (_p+1)-c;
@@ -848,7 +370,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
848
370
  }
849
371
  }
850
372
 
851
- if (newarg == NULL) goto err;
373
+ if (newarg == NULL) goto memory_err;
852
374
  curarg = newarg;
853
375
 
854
376
  touched = 1;
@@ -860,7 +382,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
860
382
  /* Add the last argument if needed */
861
383
  if (touched) {
862
384
  newargv = realloc(curargv,sizeof(char*)*(argc+1));
863
- if (newargv == NULL) goto err;
385
+ if (newargv == NULL) goto memory_err;
864
386
  curargv = newargv;
865
387
  curargv[argc++] = curarg;
866
388
  totlen += bulklen(sdslen(curarg));
@@ -872,11 +394,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
872
394
  curarg = NULL;
873
395
 
874
396
  /* Add bytes needed to hold multi bulk count */
875
- totlen += 1+intlen(argc)+2;
397
+ totlen += 1+countDigits(argc)+2;
876
398
 
877
399
  /* Build the command at protocol level */
878
400
  cmd = malloc(totlen+1);
879
- if (cmd == NULL) goto err;
401
+ if (cmd == NULL) goto memory_err;
880
402
 
881
403
  pos = sprintf(cmd,"*%d\r\n",argc);
882
404
  for (j = 0; j < argc; j++) {
@@ -894,20 +416,29 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
894
416
  *target = cmd;
895
417
  return totlen;
896
418
 
897
- err:
898
- while(argc--)
899
- sdsfree(curargv[argc]);
900
- free(curargv);
419
+ format_err:
420
+ error_type = -2;
421
+ goto cleanup;
901
422
 
902
- if (curarg != NULL)
903
- sdsfree(curarg);
423
+ memory_err:
424
+ error_type = -1;
425
+ goto cleanup;
426
+
427
+ cleanup:
428
+ if (curargv) {
429
+ while(argc--)
430
+ sdsfree(curargv[argc]);
431
+ free(curargv);
432
+ }
433
+
434
+ sdsfree(curarg);
904
435
 
905
436
  /* No need to check cmd since it is the last statement that can fail,
906
437
  * but do it anyway to be as defensive as possible. */
907
438
  if (cmd != NULL)
908
439
  free(cmd);
909
440
 
910
- return -1;
441
+ return error_type;
911
442
  }
912
443
 
913
444
  /* Format a command according to the Redis protocol. This function
@@ -917,7 +448,7 @@ err:
917
448
  * %b represents a binary safe string
918
449
  *
919
450
  * When using %b you need to provide both the pointer to the string
920
- * and the length in bytes. Examples:
451
+ * and the length in bytes as a size_t. Examples:
921
452
  *
922
453
  * len = redisFormatCommand(target, "GET %s", mykey);
923
454
  * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
@@ -928,9 +459,69 @@ int redisFormatCommand(char **target, const char *format, ...) {
928
459
  va_start(ap,format);
929
460
  len = redisvFormatCommand(target,format,ap);
930
461
  va_end(ap);
462
+
463
+ /* The API says "-1" means bad result, but we now also return "-2" in some
464
+ * cases. Force the return value to always be -1. */
465
+ if (len < 0)
466
+ len = -1;
467
+
931
468
  return len;
932
469
  }
933
470
 
471
+ /* Format a command according to the Redis protocol using an sds string and
472
+ * sdscatfmt for the processing of arguments. This function takes the
473
+ * number of arguments, an array with arguments and an array with their
474
+ * lengths. If the latter is set to NULL, strlen will be used to compute the
475
+ * argument lengths.
476
+ */
477
+ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv,
478
+ const size_t *argvlen)
479
+ {
480
+ sds cmd;
481
+ unsigned long long totlen;
482
+ int j;
483
+ size_t len;
484
+
485
+ /* Abort on a NULL target */
486
+ if (target == NULL)
487
+ return -1;
488
+
489
+ /* Calculate our total size */
490
+ totlen = 1+countDigits(argc)+2;
491
+ for (j = 0; j < argc; j++) {
492
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
493
+ totlen += bulklen(len);
494
+ }
495
+
496
+ /* Use an SDS string for command construction */
497
+ cmd = sdsempty();
498
+ if (cmd == NULL)
499
+ return -1;
500
+
501
+ /* We already know how much storage we need */
502
+ cmd = sdsMakeRoomFor(cmd, totlen);
503
+ if (cmd == NULL)
504
+ return -1;
505
+
506
+ /* Construct command */
507
+ cmd = sdscatfmt(cmd, "*%i\r\n", argc);
508
+ for (j=0; j < argc; j++) {
509
+ len = argvlen ? argvlen[j] : strlen(argv[j]);
510
+ cmd = sdscatfmt(cmd, "$%T\r\n", len);
511
+ cmd = sdscatlen(cmd, argv[j], len);
512
+ cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
513
+ }
514
+
515
+ assert(sdslen(cmd)==totlen);
516
+
517
+ *target = cmd;
518
+ return totlen;
519
+ }
520
+
521
+ void redisFreeSdsCommand(sds cmd) {
522
+ sdsfree(cmd);
523
+ }
524
+
934
525
  /* Format a command according to the Redis protocol. This function takes the
935
526
  * number of arguments, an array with arguments and an array with their
936
527
  * lengths. If the latter is set to NULL, strlen will be used to compute the
@@ -942,8 +533,12 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
942
533
  size_t len;
943
534
  int totlen, j;
944
535
 
536
+ /* Abort on a NULL target */
537
+ if (target == NULL)
538
+ return -1;
539
+
945
540
  /* Calculate number of bytes needed for the command */
946
- totlen = 1+intlen(argc)+2;
541
+ totlen = 1+countDigits(argc)+2;
947
542
  for (j = 0; j < argc; j++) {
948
543
  len = argvlen ? argvlen[j] : strlen(argv[j]);
949
544
  totlen += bulklen(len);
@@ -970,6 +565,10 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
970
565
  return totlen;
971
566
  }
972
567
 
568
+ void redisFreeCommand(char *cmd) {
569
+ free(cmd);
570
+ }
571
+
973
572
  void __redisSetError(redisContext *c, int type, const char *str) {
974
573
  size_t len;
975
574
 
@@ -982,10 +581,14 @@ void __redisSetError(redisContext *c, int type, const char *str) {
982
581
  } else {
983
582
  /* Only REDIS_ERR_IO may lack a description! */
984
583
  assert(type == REDIS_ERR_IO);
985
- strerror_r(errno,c->errstr,sizeof(c->errstr));
584
+ __redis_strerror_r(errno, c->errstr, sizeof(c->errstr));
986
585
  }
987
586
  }
988
587
 
588
+ redisReader *redisReaderCreate(void) {
589
+ return redisReaderCreateWithFunctions(&defaultFunctions);
590
+ }
591
+
989
592
  static redisContext *redisContextInit(void) {
990
593
  redisContext *c;
991
594
 
@@ -997,71 +600,192 @@ static redisContext *redisContextInit(void) {
997
600
  c->errstr[0] = '\0';
998
601
  c->obuf = sdsempty();
999
602
  c->reader = redisReaderCreate();
603
+ c->tcp.host = NULL;
604
+ c->tcp.source_addr = NULL;
605
+ c->unix_sock.path = NULL;
606
+ c->timeout = NULL;
607
+
608
+ if (c->obuf == NULL || c->reader == NULL) {
609
+ redisFree(c);
610
+ return NULL;
611
+ }
612
+
1000
613
  return c;
1001
614
  }
1002
615
 
1003
616
  void redisFree(redisContext *c) {
617
+ if (c == NULL)
618
+ return;
1004
619
  if (c->fd > 0)
1005
620
  close(c->fd);
1006
621
  if (c->obuf != NULL)
1007
622
  sdsfree(c->obuf);
1008
623
  if (c->reader != NULL)
1009
624
  redisReaderFree(c->reader);
625
+ if (c->tcp.host)
626
+ free(c->tcp.host);
627
+ if (c->tcp.source_addr)
628
+ free(c->tcp.source_addr);
629
+ if (c->unix_sock.path)
630
+ free(c->unix_sock.path);
631
+ if (c->timeout)
632
+ free(c->timeout);
1010
633
  free(c);
1011
634
  }
1012
635
 
636
+ int redisFreeKeepFd(redisContext *c) {
637
+ int fd = c->fd;
638
+ c->fd = -1;
639
+ redisFree(c);
640
+ return fd;
641
+ }
642
+
643
+ int redisReconnect(redisContext *c) {
644
+ c->err = 0;
645
+ memset(c->errstr, '\0', strlen(c->errstr));
646
+
647
+ if (c->fd > 0) {
648
+ close(c->fd);
649
+ }
650
+
651
+ sdsfree(c->obuf);
652
+ redisReaderFree(c->reader);
653
+
654
+ c->obuf = sdsempty();
655
+ c->reader = redisReaderCreate();
656
+
657
+ if (c->connection_type == REDIS_CONN_TCP) {
658
+ return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port,
659
+ c->timeout, c->tcp.source_addr);
660
+ } else if (c->connection_type == REDIS_CONN_UNIX) {
661
+ return redisContextConnectUnix(c, c->unix_sock.path, c->timeout);
662
+ } else {
663
+ /* Something bad happened here and shouldn't have. There isn't
664
+ enough information in the context to reconnect. */
665
+ __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect");
666
+ }
667
+
668
+ return REDIS_ERR;
669
+ }
670
+
1013
671
  /* Connect to a Redis instance. On error the field error in the returned
1014
672
  * context will be set to the return value of the error function.
1015
673
  * When no set of reply functions is given, the default set will be used. */
1016
674
  redisContext *redisConnect(const char *ip, int port) {
1017
- redisContext *c = redisContextInit();
675
+ redisContext *c;
676
+
677
+ c = redisContextInit();
678
+ if (c == NULL)
679
+ return NULL;
680
+
1018
681
  c->flags |= REDIS_BLOCK;
1019
682
  redisContextConnectTcp(c,ip,port,NULL);
1020
683
  return c;
1021
684
  }
1022
685
 
1023
- redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv) {
1024
- redisContext *c = redisContextInit();
686
+ redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
687
+ redisContext *c;
688
+
689
+ c = redisContextInit();
690
+ if (c == NULL)
691
+ return NULL;
692
+
1025
693
  c->flags |= REDIS_BLOCK;
1026
694
  redisContextConnectTcp(c,ip,port,&tv);
1027
695
  return c;
1028
696
  }
1029
697
 
1030
698
  redisContext *redisConnectNonBlock(const char *ip, int port) {
1031
- redisContext *c = redisContextInit();
699
+ redisContext *c;
700
+
701
+ c = redisContextInit();
702
+ if (c == NULL)
703
+ return NULL;
704
+
1032
705
  c->flags &= ~REDIS_BLOCK;
1033
706
  redisContextConnectTcp(c,ip,port,NULL);
1034
707
  return c;
1035
708
  }
1036
709
 
1037
- redisContext *redisConnectUnix(const char *path) {
710
+ redisContext *redisConnectBindNonBlock(const char *ip, int port,
711
+ const char *source_addr) {
1038
712
  redisContext *c = redisContextInit();
713
+ c->flags &= ~REDIS_BLOCK;
714
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
715
+ return c;
716
+ }
717
+
718
+ redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
719
+ const char *source_addr) {
720
+ redisContext *c = redisContextInit();
721
+ c->flags &= ~REDIS_BLOCK;
722
+ c->flags |= REDIS_REUSEADDR;
723
+ redisContextConnectBindTcp(c,ip,port,NULL,source_addr);
724
+ return c;
725
+ }
726
+
727
+ redisContext *redisConnectUnix(const char *path) {
728
+ redisContext *c;
729
+
730
+ c = redisContextInit();
731
+ if (c == NULL)
732
+ return NULL;
733
+
1039
734
  c->flags |= REDIS_BLOCK;
1040
735
  redisContextConnectUnix(c,path,NULL);
1041
736
  return c;
1042
737
  }
1043
738
 
1044
- redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv) {
1045
- redisContext *c = redisContextInit();
739
+ redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) {
740
+ redisContext *c;
741
+
742
+ c = redisContextInit();
743
+ if (c == NULL)
744
+ return NULL;
745
+
1046
746
  c->flags |= REDIS_BLOCK;
1047
747
  redisContextConnectUnix(c,path,&tv);
1048
748
  return c;
1049
749
  }
1050
750
 
1051
751
  redisContext *redisConnectUnixNonBlock(const char *path) {
1052
- redisContext *c = redisContextInit();
752
+ redisContext *c;
753
+
754
+ c = redisContextInit();
755
+ if (c == NULL)
756
+ return NULL;
757
+
1053
758
  c->flags &= ~REDIS_BLOCK;
1054
759
  redisContextConnectUnix(c,path,NULL);
1055
760
  return c;
1056
761
  }
1057
762
 
763
+ redisContext *redisConnectFd(int fd) {
764
+ redisContext *c;
765
+
766
+ c = redisContextInit();
767
+ if (c == NULL)
768
+ return NULL;
769
+
770
+ c->fd = fd;
771
+ c->flags |= REDIS_BLOCK | REDIS_CONNECTED;
772
+ return c;
773
+ }
774
+
1058
775
  /* Set read/write timeout on a blocking socket. */
1059
- int redisSetTimeout(redisContext *c, struct timeval tv) {
776
+ int redisSetTimeout(redisContext *c, const struct timeval tv) {
1060
777
  if (c->flags & REDIS_BLOCK)
1061
778
  return redisContextSetTimeout(c,tv);
1062
779
  return REDIS_ERR;
1063
780
  }
1064
781
 
782
+ /* Enable connection KeepAlive. */
783
+ int redisEnableKeepAlive(redisContext *c) {
784
+ if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK)
785
+ return REDIS_ERR;
786
+ return REDIS_OK;
787
+ }
788
+
1065
789
  /* Use this function to handle a read event on the descriptor. It will try
1066
790
  * and read some bytes from the socket and feed them to the reply parser.
1067
791
  *
@@ -1077,7 +801,7 @@ int redisBufferRead(redisContext *c) {
1077
801
 
1078
802
  nread = read(c->fd,buf,sizeof(buf));
1079
803
  if (nread == -1) {
1080
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
804
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1081
805
  /* Try again later */
1082
806
  } else {
1083
807
  __redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1114,7 +838,7 @@ int redisBufferWrite(redisContext *c, int *done) {
1114
838
  if (sdslen(c->obuf) > 0) {
1115
839
  nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
1116
840
  if (nwritten == -1) {
1117
- if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
841
+ if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
1118
842
  /* Try again later */
1119
843
  } else {
1120
844
  __redisSetError(c,REDIS_ERR_IO,NULL);
@@ -1180,7 +904,7 @@ int redisGetReply(redisContext *c, void **reply) {
1180
904
  * is used, you need to call redisGetReply yourself to retrieve
1181
905
  * the reply (or replies in pub/sub).
1182
906
  */
1183
- int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
907
+ int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
1184
908
  sds newbuf;
1185
909
 
1186
910
  newbuf = sdscatlen(c->obuf,cmd,len);
@@ -1193,6 +917,15 @@ int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
1193
917
  return REDIS_OK;
1194
918
  }
1195
919
 
920
+ int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {
921
+
922
+ if (__redisAppendCommand(c, cmd, len) != REDIS_OK) {
923
+ return REDIS_ERR;
924
+ }
925
+
926
+ return REDIS_OK;
927
+ }
928
+
1196
929
  int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1197
930
  char *cmd;
1198
931
  int len;
@@ -1201,6 +934,9 @@ int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
1201
934
  if (len == -1) {
1202
935
  __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1203
936
  return REDIS_ERR;
937
+ } else if (len == -2) {
938
+ __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string");
939
+ return REDIS_ERR;
1204
940
  }
1205
941
 
1206
942
  if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
@@ -1223,21 +959,21 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
1223
959
  }
1224
960
 
1225
961
  int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
1226
- char *cmd;
962
+ sds cmd;
1227
963
  int len;
1228
964
 
1229
- len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
965
+ len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
1230
966
  if (len == -1) {
1231
967
  __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
1232
968
  return REDIS_ERR;
1233
969
  }
1234
970
 
1235
971
  if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
1236
- free(cmd);
972
+ sdsfree(cmd);
1237
973
  return REDIS_ERR;
1238
974
  }
1239
975
 
1240
- free(cmd);
976
+ sdsfree(cmd);
1241
977
  return REDIS_OK;
1242
978
  }
1243
979