durable_rules 0.33.13 → 0.34.01

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